1- document . addEventListener ( 'DOMContentLoaded' , async ( ) => {
2- const navContainer = document . getElementById ( 'nav-container' ) ;
3- const previewContainer = document . getElementById ( 'preview-container' ) ;
4- const codeContainer = document . getElementById ( 'code-container' ) ;
5- const titleEl = document . getElementById ( 'component-title' ) ;
6- const idEl = document . getElementById ( 'component-id' ) ;
7- const codeWrapper = document . getElementById ( 'code-block-wrapper' ) ;
8-
9- try {
10- const response = await fetch ( 'data/components.json' ) ;
11- const components = await response . json ( ) ;
12- renderNavigation ( components ) ;
13- } catch ( error ) {
14- console . error ( 'Failed to load library:' , error ) ;
15- }
1+ function formatHTML ( html ) {
2+ if ( ! html ) return '' ;
3+
4+ let formatted = html . replace ( / > \s + < / g, '><' ) . trim ( ) ;
5+
6+ formatted = formatted
7+ . replace ( / ( < (? ! \/ ) (? ! s p a n | s t r o n g | b | i | e m | s m a l l ) [ ^ > ] + > ) / g, '\n$1' )
8+ . replace ( / ( < \/ (? ! s p a n | s t r o n g | b | i | e m | s m a l l ) [ ^ > ] + > ) / g, '\n$1' )
9+ . replace ( / \n \n / g, '\n' ) ;
1610
17- function renderNavigation ( components ) {
18- const categories = { } ;
19-
20- components . forEach ( ( c ) => {
21- if ( ! categories [ c . category ] ) categories [ c . category ] = [ ] ;
22- categories [ c . category ] . push ( c ) ;
23- } ) ;
24-
25- Object . keys ( categories ) . forEach ( ( cat ) => {
26- const group = document . createElement ( 'div' ) ;
27- group . className = 'mb-6' ;
28-
29- const title = document . createElement ( 'h3' ) ;
30- title . className =
31- 'text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2 px-2' ;
32- title . textContent = cat ;
33- group . appendChild ( title ) ;
34-
35- categories [ cat ] . forEach ( ( item ) => {
36- const btn = document . createElement ( 'button' ) ;
37- btn . className =
38- 'w-full text-left px-3 py-2 text-sm text-gray-600 rounded-lg hover:bg-gray-100 hover:text-gray-900 transition-colors mb-1' ;
39- btn . textContent = item . name ;
40- btn . onclick = ( ) => loadComponent ( item ) ;
41- group . appendChild ( btn ) ;
42- } ) ;
43-
44- navContainer . appendChild ( group ) ;
45- } ) ;
46- }
11+ const lines = formatted . split ( '\n' ) ;
12+ let indentLevel = 0 ;
13+ const tab = ' ' ;
14+ let result = '' ;
15+
16+ lines . forEach ( ( line ) => {
17+ line = line . trim ( ) ;
18+ if ( ! line ) return ;
4719
48- async function loadComponent ( item ) {
49- try {
50- const response = await fetch ( item . path ) ;
51- const html = await response . text ( ) ;
52-
53- previewContainer . innerHTML = html ;
54- codeContainer . textContent = html ;
55- titleEl . textContent = item . name ;
56- idEl . textContent = item . id ;
57- codeWrapper . classList . remove ( 'hidden' ) ;
58- } catch ( e ) {
59- previewContainer . innerHTML = '<span class="text-red-500">Error loading component</span>' ;
20+ const isClosing = line . match ( / ^ < \/ / ) ;
21+ const isSelfClosing = line . match ( / \/ > $ / ) || line . match ( / ^ < ( i m g | i n p u t | b r | h r | m e t a | l i n k ) / ) ;
22+
23+ if ( isClosing && indentLevel > 0 ) {
24+ indentLevel -- ;
6025 }
61- }
62- } ) ;
26+
27+ result += tab . repeat ( indentLevel ) + line + '\n' ;
28+
29+ if ( ! isClosing && ! isSelfClosing ) {
30+ indentLevel ++ ;
31+ }
32+ } ) ;
33+
34+ return result . trim ( ) ;
35+ }
6336
6437window . copyCode = ( ) => {
6538 const code = document . getElementById ( 'code-container' ) . textContent ;
66- navigator . clipboard . writeText ( code ) ;
67- alert ( 'Copied to clipboard!' ) ;
68- } ;
39+ navigator . clipboard . writeText ( code ) . then ( ( ) => {
40+ alert ( 'Snippet copied to clipboard' ) ;
41+ } ) ;
42+ } ;
43+
44+ function initTheme ( ) {
45+ const savedTheme = localStorage . getItem ( 'theme' ) || 'system' ;
46+ setTheme ( savedTheme , false ) ;
47+ }
48+
49+ window . setTheme = ( mode , save = true ) => {
50+ if ( save ) localStorage . setItem ( 'theme' , mode ) ;
51+
52+ const isDark =
53+ mode === 'dark' ||
54+ ( mode === 'system' &&
55+ window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches ) ;
56+
57+ if ( isDark ) {
58+ document . documentElement . classList . add ( 'dark' ) ;
59+ } else {
60+ document . documentElement . classList . remove ( 'dark' ) ;
61+ }
62+
63+ updateThemeUI ( mode ) ;
64+ } ;
65+
66+ function updateThemeUI ( mode ) {
67+ const slider = document . getElementById ( 'theme-slider' ) ;
68+ if ( ! slider ) return ;
69+
70+ const positions = {
71+ 'system' : '0px' ,
72+ 'light' : '28px' ,
73+ 'dark' : '56px'
74+ } ;
75+
76+ slider . style . transform = `translateX(${ positions [ mode ] } )` ;
77+ }
78+
79+ document . addEventListener ( 'DOMContentLoaded' , ( ) => {
80+ initTheme ( ) ;
81+
82+ const codeContainer = document . getElementById ( 'code-container' ) ;
83+
84+ if ( window . COMPONENT_DATA && codeContainer ) {
85+ codeContainer . textContent = formatHTML ( window . COMPONENT_DATA ) ;
86+ }
87+ } ) ;
88+
89+ window . matchMedia ( '(prefers-color-scheme: dark)' ) . addEventListener ( 'change' , e => {
90+ if ( localStorage . getItem ( 'theme' ) === 'system' ) {
91+ setTheme ( 'system' , false ) ;
92+ }
93+ } ) ;
0 commit comments