1+ <!DOCTYPE html>
2+ < html lang ="en ">
3+ < head >
4+ < meta charset ="UTF-8 ">
5+ < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
6+ < title > mdtail - Split Terminal Demo</ title >
7+ < style >
8+ * {
9+ margin : 0 ;
10+ padding : 0 ;
11+ box-sizing : border-box;
12+ }
13+
14+ body {
15+ background : # 1e1e1e ;
16+ font-family : 'Monaco' , 'Menlo' , 'Courier New' , monospace;
17+ display : flex;
18+ justify-content : center;
19+ align-items : center;
20+ min-height : 100vh ;
21+ padding : 20px ;
22+ }
23+
24+ .terminal-container {
25+ background : # 000 ;
26+ border-radius : 8px ;
27+ box-shadow : 0 20px 60px rgba (0 , 0 , 0 , 0.5 );
28+ overflow : hidden;
29+ width : 1200px ;
30+ max-width : 100% ;
31+ height : 600px ;
32+ }
33+
34+ .terminal-header {
35+ background : linear-gradient (# 504b45 0% , # 3c3b37 100% );
36+ padding : 10px ;
37+ display : flex;
38+ align-items : center;
39+ }
40+
41+ .terminal-controls {
42+ display : flex;
43+ gap : 8px ;
44+ }
45+
46+ .terminal-control {
47+ width : 12px ;
48+ height : 12px ;
49+ border-radius : 50% ;
50+ }
51+
52+ .close { background : # ff5f56 ; }
53+ .minimize { background : # ffbd2e ; }
54+ .maximize { background : # 27c93f ; }
55+
56+ .terminal-title {
57+ flex : 1 ;
58+ text-align : center;
59+ color : # ccc ;
60+ font-size : 14px ;
61+ }
62+
63+ .terminal-split {
64+ display : flex;
65+ height : calc (100% - 40px );
66+ }
67+
68+ .terminal-pane {
69+ flex : 1 ;
70+ padding : 20px ;
71+ color : # d4d4d4 ;
72+ font-size : 13px ;
73+ line-height : 1.6 ;
74+ overflow-y : auto;
75+ overflow-x : hidden;
76+ position : relative;
77+ }
78+
79+ .terminal-left {
80+ border-right : 1px solid # 333 ;
81+ background : # 0c0c0c ;
82+ }
83+
84+ .terminal-right {
85+ background : # 000 ;
86+ }
87+
88+ .prompt {
89+ color : # 569cd6 ;
90+ }
91+
92+ .command {
93+ color : # d4d4d4 ;
94+ }
95+
96+ .comment {
97+ color : # 608b4e ;
98+ }
99+
100+ .output {
101+ color : # d4d4d4 ;
102+ margin : 10px 0 ;
103+ }
104+
105+ .border {
106+ color : # 764ba2 ;
107+ font-weight : bold;
108+ display : block;
109+ overflow : hidden;
110+ white-space : nowrap;
111+ }
112+
113+ .border ::after {
114+ content : '══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════' ;
115+ display : inline-block;
116+ }
117+
118+ .divider {
119+ color : # 666 ;
120+ display : block;
121+ overflow : hidden;
122+ white-space : nowrap;
123+ }
124+
125+ .divider ::after {
126+ content : '──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────' ;
127+ display : inline-block;
128+ }
129+
130+ .filename {
131+ color : # 667eea ;
132+ text-align : center;
133+ font-weight : bold;
134+ text-transform : uppercase;
135+ }
136+
137+ .content {
138+ color : # d4d4d4 ;
139+ white-space : pre-wrap;
140+ font-family : inherit;
141+ }
142+
143+ .content h1 { color : # 569cd6 ; margin : 10px 0 ; }
144+ .content h2 { color : # 608b4e ; margin : 10px 0 ; }
145+ .content li { margin-left : 20px ; }
146+
147+ .typing {
148+ display : inline;
149+ border-right : 2px solid # 0f0 ;
150+ animation : blink 1s infinite;
151+ }
152+
153+ @keyframes blink {
154+ 0% , 50% { border-color : # 0f0 ; }
155+ 51% , 100% { border-color : transparent; }
156+ }
157+
158+ .hidden {
159+ display : none;
160+ }
161+
162+ .navigation {
163+ color : # 569cd6 ;
164+ text-align : center;
165+ margin-top : 10px ;
166+ }
167+
168+ .cursor {
169+ display : inline-block;
170+ width : 8px ;
171+ height : 16px ;
172+ background : # 0f0 ;
173+ animation : blink 1s infinite;
174+ vertical-align : text-bottom;
175+ }
176+
177+ .tmux-status {
178+ position : absolute;
179+ bottom : 0 ;
180+ left : 0 ;
181+ right : 0 ;
182+ background : # 222 ;
183+ color : # fff ;
184+ padding : 2px 10px ;
185+ font-size : 12px ;
186+ display : flex;
187+ justify-content : space-between;
188+ }
189+
190+ .tmux-left {
191+ color : # 0f0 ;
192+ }
193+
194+ .tmux-center {
195+ color : # 569cd6 ;
196+ }
197+
198+ .tmux-right {
199+ color : # 764ba2 ;
200+ }
201+
202+ @media (max-width : 768px ) {
203+ .terminal-split {
204+ flex-direction : column;
205+ }
206+ .terminal-left {
207+ border-right : none;
208+ border-bottom : 1px solid # 333 ;
209+ }
210+ }
211+ </ style >
212+ </ head >
213+ < body >
214+ < div class ="terminal-container ">
215+ < div class ="terminal-header ">
216+ < div class ="terminal-controls ">
217+ < div class ="terminal-control close "> </ div >
218+ < div class ="terminal-control minimize "> </ div >
219+ < div class ="terminal-control maximize "> </ div >
220+ </ div >
221+ < div class ="terminal-title "> Terminal - tmux session: mdtail-demo</ div >
222+ </ div >
223+ < div class ="terminal-split ">
224+ <!-- Left Pane - Command Line -->
225+ < div class ="terminal-pane terminal-left " id ="left-pane ">
226+ < div id ="left-content "> </ div >
227+ < div class ="tmux-status ">
228+ < span class ="tmux-left "> [0] 0:bash*</ span >
229+ < span class ="tmux-center "> "mdtail-demo"</ span >
230+ < span class ="tmux-right "> 14:23</ span >
231+ </ div >
232+ </ div >
233+
234+ <!-- Right Pane - mdtail -->
235+ < div class ="terminal-pane terminal-right " id ="right-pane ">
236+ < div id ="right-content "> </ div >
237+ < div class ="tmux-status ">
238+ < span class ="tmux-left "> [1] 1:mdtail</ span >
239+ < span class ="tmux-center "> "mdtail-demo"</ span >
240+ < span class ="tmux-right "> 14:23</ span >
241+ </ div >
242+ </ div >
243+ </ div >
244+ </ div >
245+
246+ < script >
247+ async function typeText ( text , element , speed = 50 ) {
248+ for ( let i = 0 ; i < text . length ; i ++ ) {
249+ element . innerHTML += text [ i ] ;
250+ await new Promise ( r => setTimeout ( r , speed ) ) ;
251+ }
252+ }
253+
254+ async function runRightPane ( ) {
255+ const container = document . getElementById ( 'right-content' ) ;
256+
257+ // Initial prompt
258+ const prompt1 = document . createElement ( 'span' ) ;
259+ prompt1 . className = 'prompt' ;
260+ prompt1 . innerHTML = '$ ' ;
261+ container . appendChild ( prompt1 ) ;
262+
263+ await new Promise ( r => setTimeout ( r , 500 ) ) ;
264+
265+ // Type npm install command
266+ const npmCmd = document . createElement ( 'span' ) ;
267+ npmCmd . className = 'command' ;
268+ container . appendChild ( npmCmd ) ;
269+ await typeText ( 'npm install -g mdtail' , npmCmd , 60 ) ;
270+
271+ await new Promise ( r => setTimeout ( r , 500 ) ) ;
272+ container . appendChild ( document . createTextNode ( '\n' ) ) ;
273+
274+ // Show npm installation output
275+ const npmOutput = document . createElement ( 'div' ) ;
276+ npmOutput . className = 'output' ;
277+ npmOutput . style . color = '#888' ;
278+ npmOutput . textContent = 'added 1 package in 2s' ;
279+ container . appendChild ( npmOutput ) ;
280+
281+ await new Promise ( r => setTimeout ( r , 1000 ) ) ;
282+
283+ // Second prompt - no extra newline
284+ const prompt2 = document . createElement ( 'span' ) ;
285+ prompt2 . className = 'prompt' ;
286+ prompt2 . innerHTML = '$ ' ;
287+ container . appendChild ( prompt2 ) ;
288+
289+ await new Promise ( r => setTimeout ( r , 500 ) ) ;
290+
291+ // Type mdtail command
292+ const mdtailCmd = document . createElement ( 'span' ) ;
293+ mdtailCmd . className = 'command' ;
294+ container . appendChild ( mdtailCmd ) ;
295+ await typeText ( 'mdtail *.md' , mdtailCmd , 60 ) ;
296+
297+ await new Promise ( r => setTimeout ( r , 500 ) ) ;
298+ container . appendChild ( document . createTextNode ( '\n\n' ) ) ;
299+
300+ // Show mdtail output with tabs
301+ showMdtailOutput ( ) ;
302+ }
303+
304+ function showMdtailOutput ( ) {
305+ const container = document . getElementById ( 'right-content' ) ;
306+ const mdtailOutput = document . createElement ( 'div' ) ;
307+ mdtailOutput . innerHTML = `
308+ <span class="border"></span>
309+ <div style="color: #d4d4d4; padding: 2px 0;">
310+ <span style="font-weight: bold; color: #fff;">[README.md]</span> │ TODO.md
311+ </div>
312+ <span class="divider"></span>
313+
314+ <div class="content" id="mdtail-content"># My Project
315+
316+ A simple demo application showcasing mdtail functionality.
317+
318+ ## Quick Start
319+
320+ 1. Install dependencies: npm install
321+ 2. Run the app: npm start
322+ 3. View docs: mdtail *.md
323+
324+ ## Features
325+
326+ - Live markdown preview
327+ - File watching
328+ - Tab navigation</div>
329+
330+ <span class="border"></span>
331+ <div class="navigation">Tab 1 of 2 │ ← → Navigate │ Ctrl+C Exit</div>` ;
332+
333+ container . appendChild ( mdtailOutput ) ;
334+
335+ // Simulate switching to TODO.md after 3 seconds
336+ setTimeout ( ( ) => {
337+ mdtailOutput . innerHTML = `
338+ <span class="border"></span>
339+ <div style="color: #d4d4d4; padding: 2px 0;">
340+ README.md │ <span style="font-weight: bold; color: #fff;">[TODO.md]</span>
341+ </div>
342+ <span class="divider"></span>
343+
344+ <div class="content" id="mdtail-content"># TODO List
345+
346+ ## This Week
347+ - [x] Setup project
348+ - [x] Write documentation
349+ - [ ] Add tests
350+ - [ ] Deploy to production
351+
352+ ## Next Sprint
353+ - [ ] User authentication
354+ - [ ] API integration
355+ - [ ] Performance optimization</div>
356+
357+ <span class="border"></span>
358+ <div class="navigation">Tab 2 of 2 │ ← → Navigate │ Ctrl+C Exit</div>` ;
359+ } , 3000 ) ;
360+ }
361+
362+ async function runLeftPane ( ) {
363+ const container = document . getElementById ( 'left-content' ) ;
364+
365+ // Just show a prompt with cursor
366+ const prompt = document . createElement ( 'span' ) ;
367+ prompt . className = 'prompt' ;
368+ prompt . innerHTML = '$ ' ;
369+ container . appendChild ( prompt ) ;
370+
371+ // Add blinking cursor
372+ const cursor = document . createElement ( 'span' ) ;
373+ cursor . className = 'cursor' ;
374+ container . appendChild ( cursor ) ;
375+ }
376+
377+ // Start the demo
378+ window . addEventListener ( 'load' , ( ) => {
379+ runLeftPane ( ) ;
380+ runRightPane ( ) ;
381+ } ) ;
382+ </ script >
383+ </ body >
384+ </ html >
0 commit comments