1717 brand : {
1818 DEFAULT : '#E14817' ,
1919 hover : '#C23E14'
20+ } ,
21+ terminal : {
22+ text : '#F2951C' /* Custom console font color */
2023 }
2124 }
2225 }
6265 display : flex;
6366 flex-direction : column;
6467 padding-bottom : 2rem ;
65- min-height : 0 ; /* Crucial for flex child to allow inner scrolling */
68+ min-height : 0 ;
6669 }
6770
6871 .terminal-container {
6972 flex : 1 ;
7073 display : flex;
7174 flex-direction : column;
72- min-height : 0 ; /* Crucial for flex child to allow inner scrolling */
75+ min-height : 0 ;
7376 }
7477
7578 # console-log-text {
7679 flex : 1 ;
77- overflow-y : auto; /* Enables vertical scrolling */
80+ overflow-y : auto;
7881 word-wrap : break-word;
7982 }
8083
8184 /* Prevent layout shift during auto-scroll */
8285 .log-entry {
8386 margin-bottom : 0.5rem ;
84- white-space : pre-wrap;
85- word-break : break-all;
87+ font-family : ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono" , "Courier New" , monospace;
88+ }
89+
90+ /* Hide the default triangle marker for summary */
91+ summary ::-webkit-details-marker {
92+ display : none;
93+ }
94+ summary {
95+ list-style : none;
8696 }
8797 </ style >
8898</ head >
8999< body class ="bg-gray-50 font-sans text-gray-800 ">
90100
91- < div class ="main-container w-[1024px] max-w-[1024px] mx-auto pt-8 px-4 ">
101+ < div class ="main-container w-[1024px] max-w-[1024px] mx-auto pt-6 px-4 ">
92102
93103 <!-- Header Section -->
94- < div class ="text-center mb-6 shrink-0 ">
104+ < div class ="text-center mb-4 shrink-0 ">
95105 < h1 class ="text-4xl font-extrabold text-gray-900 tracking-tight mb-2 ">
96- < span class ="block text-brand "> Labs64</ span >
97- < a href ="https://netlicensing.io/ " target ="_blank " class ="hover:text-brand-hover transition-colors ">
98- NetLicensing JavaScript Client
106+ < a class ="block text-brand " href ="https://netlicensing.io/ " target ="_blank " class ="hover:text-brand-hover transition-colors ">
107+ Labs64 NetLicensing
99108 </ a >
109+ < span class ="block "> JavaScript Client</ span >
100110 </ h1 >
101- < p class ="mt-2 text-lg text-gray-500 max-w-2xl mx-auto ">
111+ < p class ="mt-1 text-base text-gray-500 max-w-2xl mx-auto ">
102112 Interactive demo showcasing < a href ="https://netlicensing.io/wiki/restful-api " target ="_blank " class ="text-brand hover:underline "> RESTful API</ a > access.
103113 </ p >
104114 </ div >
105115
106116 <!-- Controls Section -->
107- < div class ="flex justify-center gap-4 mb-6 shrink-0 ">
117+ < div class ="flex justify-center gap-3 mb-4 shrink-0 flex-wrap ">
108118 < button
109119 onclick ="NetLicensingDemo() "
110- class ="inline-flex items-center px-6 py-2 border border-transparent text-base font-medium rounded-md shadow-sm text-white bg-brand hover:bg-brand-hover focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-brand transition-colors duration-200 ">
111- < svg class ="w-5 h-5 mr-2 -ml-1 " fill ="none " stroke ="currentColor " viewBox ="0 0 24 24 " xmlns ="http://www.w3.org/2000/svg "> < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z "> </ path > < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M21 12a9 9 0 11-18 0 9 9 0 0118 0z "> </ path > </ svg >
120+ class ="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-brand hover:bg-brand-hover focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-brand transition-colors duration-200 ">
121+ < svg class ="w-4 h-4 mr-2 " fill ="none " stroke ="currentColor " viewBox ="0 0 24 24 " xmlns ="http://www.w3.org/2000/svg "> < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z "> </ path > < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M21 12a9 9 0 11-18 0 9 9 0 0118 0z "> </ path > </ svg >
112122 Execute Demo
113123 </ button >
114124
115125 < button
116126 onclick ="clearBox('console-log-text') "
117- class ="inline-flex items-center px-6 py-2 border border-gray-300 text-base font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-brand transition-colors duration-200 shadow-sm ">
118- < svg class ="w-5 h-5 mr-2 -ml-1 text-gray-500 " fill ="none " stroke ="currentColor " viewBox ="0 0 24 24 " xmlns ="http://www.w3.org/2000/svg "> < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16 "> </ path > </ svg >
127+ class ="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none transition-colors duration-200 shadow-sm ">
128+ < svg class ="w-4 h-4 mr-2 text-gray-500 " fill ="none " stroke ="currentColor " viewBox ="0 0 24 24 " xmlns ="http://www.w3.org/2000/svg "> < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16 "> </ path > </ svg >
119129 Clear Console
120130 </ button >
131+
132+ <!-- New Navigability Buttons -->
133+ < button
134+ onclick ="toggleAllLogs(true) "
135+ class ="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none transition-colors duration-200 shadow-sm ">
136+ < svg class ="w-4 h-4 mr-2 text-gray-500 " fill ="none " stroke ="currentColor " viewBox ="0 0 24 24 " xmlns ="http://www.w3.org/2000/svg "> < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M19 9l-7 7-7-7 "> </ path > </ svg >
137+ Expand All
138+ </ button >
139+
140+ < button
141+ onclick ="toggleAllLogs(false) "
142+ class ="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none transition-colors duration-200 shadow-sm ">
143+ < svg class ="w-4 h-4 mr-2 text-gray-500 " fill ="none " stroke ="currentColor " viewBox ="0 0 24 24 " xmlns ="http://www.w3.org/2000/svg "> < path stroke-linecap ="round " stroke-linejoin ="round " stroke-width ="2 " d ="M5 15l7-7 7 7 "> </ path > </ svg >
144+ Collapse All
145+ </ button >
121146 </ div >
122147
123148 <!-- Terminal Output Section -->
@@ -132,15 +157,27 @@ <h1 class="text-4xl font-extrabold text-gray-900 tracking-tight mb-2">
132157 < div class ="mx-auto text-gray-400 text-xs font-mono "> demo-output.log</ div >
133158 </ div >
134159
135- <!-- Output container now takes up remaining screen height AND allows scrolling -->
136- < div class ="p-4 font-mono text-sm w-full " id ="console-log-text ">
137- < div class ="text-gray-500 mb-2 "> Ready. Click 'Execute Demo' to start the NetLicensing API simulation...</ div >
160+ <!-- Output container -->
161+ < div class ="p-4 text-sm w-full " id ="console-log-text ">
162+ < div class ="text-gray-500 mb-2 font-mono "> Ready. Click 'Execute Demo' to start the NetLicensing API simulation...</ div >
138163 </ div >
139164 </ div >
140165 </ div >
141166
142167 <!-- Intercept Console Output -->
143168 < script >
169+ // Helper function for the Expand/Collapse buttons
170+ function toggleAllLogs ( expand ) {
171+ const details = document . querySelectorAll ( '#console-log-text details' ) ;
172+ details . forEach ( detail => {
173+ if ( expand ) {
174+ detail . setAttribute ( 'open' , '' ) ;
175+ } else {
176+ detail . removeAttribute ( 'open' ) ;
177+ }
178+ } ) ;
179+ }
180+
144181 ( function ( ) {
145182 const oldLog = console . log ;
146183 const oldError = console . error ;
@@ -165,28 +202,64 @@ <h1 class="text-4xl font-extrabold text-gray-900 tracking-tight mb-2">
165202
166203 function appendLog ( args , colorClass , prefixChar = '>' ) {
167204 const msg = formatArgs ( args ) ;
168- const div = document . createElement ( 'div' ) ;
169- div . className = `log-entry ${ colorClass } ` ;
205+ const lines = msg . split ( '\n' ) ;
206+
207+ // If it's a multi-line output (like an API JSON response), make it foldable
208+ if ( lines . length > 1 ) {
209+ const details = document . createElement ( 'details' ) ;
210+ details . className = `log-entry ${ colorClass } group` ;
211+
212+ const summary = document . createElement ( 'summary' ) ;
213+ summary . className = 'cursor-pointer hover:opacity-80 transition-opacity outline-none flex items-start select-none' ;
214+
215+ // Arrow indicator that rotates when expanded
216+ const arrow = document . createElement ( 'span' ) ;
217+ arrow . className = 'text-[#E14817] mr-2 font-bold transform transition-transform group-open:rotate-90 inline-block w-3 flex-shrink-0 text-center' ;
218+ arrow . textContent = prefixChar ;
170219
171- const prefix = document . createElement ( 'span' ) ;
172- prefix . className = 'text-[#E14817] mr-2 select-none font-bold' ;
173- prefix . textContent = prefixChar ;
220+ const summaryText = document . createElement ( 'span' ) ;
221+ // Show the first line with an ellipsis, so the user knows there is hidden data
222+ summaryText . textContent = lines [ 0 ] + ' ...' ;
223+ summaryText . className = 'truncate' ;
174224
175- div . appendChild ( prefix ) ;
176- div . appendChild ( document . createTextNode ( msg ) ) ;
225+ summary . appendChild ( arrow ) ;
226+ summary . appendChild ( summaryText ) ;
177227
178- logger . appendChild ( div ) ;
228+ const content = document . createElement ( 'div' ) ;
229+ // Indent the expanded JSON, add a subtle border on the left
230+ content . className = 'pl-4 ml-[0.35rem] border-l-2 border-gray-700 mt-1 whitespace-pre-wrap break-all opacity-90' ;
231+ content . textContent = lines . slice ( 1 ) . join ( '\n' ) ;
232+
233+ details . appendChild ( summary ) ;
234+ details . appendChild ( content ) ;
235+ logger . appendChild ( details ) ;
236+ }
237+ // Single line output (like a basic string log)
238+ else {
239+ const div = document . createElement ( 'div' ) ;
240+ div . className = `log-entry ${ colorClass } flex items-start` ;
241+
242+ const prefix = document . createElement ( 'span' ) ;
243+ prefix . className = 'text-[#E14817] mr-2 select-none font-bold inline-block w-3 flex-shrink-0 text-center' ;
244+ prefix . textContent = prefixChar ;
245+
246+ const text = document . createElement ( 'span' ) ;
247+ text . className = 'whitespace-pre-wrap break-all' ;
248+ text . textContent = msg ;
249+
250+ div . appendChild ( prefix ) ;
251+ div . appendChild ( text ) ;
252+ logger . appendChild ( div ) ;
253+ }
179254
180- // Ensure the scroll goes all the way to the newly added item
181- // Use requestAnimationFrame to ensure the DOM has updated before calculating height
182255 requestAnimationFrame ( ( ) => {
183256 logger . scrollTop = logger . scrollHeight ;
184257 } ) ;
185258 }
186259
187260 console . log = function ( ) {
188261 oldLog . apply ( console , arguments ) ;
189- appendLog ( arguments , 'text-green-400 ' ) ;
262+ appendLog ( arguments , 'text-terminal-text ' ) ;
190263 } ;
191264
192265 console . error = function ( ) {
@@ -211,7 +284,7 @@ <h1 class="text-4xl font-extrabold text-gray-900 tracking-tight mb-2">
211284 window . clearBox = function ( elementID ) {
212285 const el = document . getElementById ( elementID ) ;
213286 if ( el ) {
214- el . innerHTML = '<div class="text-gray-500 mb-2">Console cleared. Ready.</div>' ;
287+ el . innerHTML = '<div class="text-gray-500 mb-2 font-mono ">Console cleared. Ready.</div>' ;
215288 }
216289 } ;
217290 } ) ( ) ;
0 commit comments