@@ -8,6 +8,7 @@ document.addEventListener('DOMContentLoaded', function() {
88 const outputModeSel = document . getElementById ( 'outputMode' ) ;
99 const langSelect = document . getElementById ( 'langSelect' ) ;
1010 const saveInputToggle = document . getElementById ( 'saveInputToggle' ) ;
11+ const themeSelect = document . getElementById ( 'themeSelect' ) ;
1112 const downloadJsonBtn = document . getElementById ( 'downloadJsonBtn' ) ;
1213 const downloadCsvBtn = document . getElementById ( 'downloadCsvBtn' ) ;
1314 const expandJsonToggle = document . getElementById ( 'expandJsonToggle' ) ;
@@ -27,6 +28,7 @@ document.addEventListener('DOMContentLoaded', function() {
2728 const I18N = {
2829 en : {
2930 langLabel : 'Language' ,
31+ themeLabel : 'Theme' ,
3032 title : 'SQL to JSON/Table Converter' ,
3133 inputSectionTitle : 'Input & Actions' ,
3234 sqlLabel : 'Paste your SQL here (you can include CREATE TABLE and multiple INSERT statements):' ,
@@ -59,6 +61,7 @@ document.addEventListener('DOMContentLoaded', function() {
5961 } ,
6062 zh : {
6163 langLabel : '语言' ,
64+ themeLabel : '主题' ,
6265 title : 'SQL 插入语句 ➜ JSON 与 HTML 表格' ,
6366 inputSectionTitle : '输入与操作' ,
6467 sqlLabel : '在此粘贴 SQL(可包含 CREATE TABLE 与多条 INSERT 语句):' ,
@@ -97,6 +100,7 @@ document.addEventListener('DOMContentLoaded', function() {
97100 function applyI18n ( ) {
98101 const setText = ( id , text ) => { const el = document . getElementById ( id ) ; if ( el ) el . textContent = text ; } ;
99102 setText ( 'langLabel' , t ( 'langLabel' ) ) ;
103+ setText ( 'themeLabel' , t ( 'themeLabel' ) ) ;
100104 setText ( 'title' , t ( 'title' ) ) ;
101105 setText ( 'inputSectionTitle' , t ( 'inputSectionTitle' ) ) ;
102106 setText ( 'sqlLabel' , t ( 'sqlLabel' ) ) ;
@@ -716,6 +720,7 @@ document.addEventListener('DOMContentLoaded', function() {
716720 const LS_LANG = 'sql2table.lang' ;
717721 const LS_SAVE_INPUT = 'sql2table.saveInput' ;
718722 const LS_INPUT = 'sql2table.input' ;
723+ const LS_THEME = 'sql2table.theme' ;
719724
720725 // Load persisted settings
721726 try {
@@ -728,6 +733,9 @@ document.addEventListener('DOMContentLoaded', function() {
728733 const savedInput = localStorage . getItem ( LS_INPUT ) ;
729734 if ( savedInput && sqlInput ) sqlInput . value = savedInput ;
730735 }
736+ const savedTheme = localStorage . getItem ( LS_THEME ) || 'system' ;
737+ if ( themeSelect ) themeSelect . value = savedTheme ;
738+ applyTheme ( savedTheme ) ;
731739 } catch ( _ ) { }
732740
733741 // language switching
@@ -759,6 +767,30 @@ document.addEventListener('DOMContentLoaded', function() {
759767 // initial i18n on load
760768 applyI18n ( ) ;
761769
770+ // Theme handling
771+ function applyTheme ( mode ) {
772+ const root = document . documentElement ;
773+ const mq = window . matchMedia ( '(prefers-color-scheme: dark)' ) ;
774+ function setFromSystem ( ) {
775+ root . setAttribute ( 'data-bs-theme' , mq . matches ? 'dark' : 'light' ) ;
776+ }
777+ if ( mode === 'dark' || mode === 'light' ) {
778+ root . setAttribute ( 'data-bs-theme' , mode ) ;
779+ // remove listener if any
780+ try { mq . removeEventListener ( 'change' , onMqlChange ) ; } catch ( _ ) { }
781+ } else {
782+ setFromSystem ( ) ;
783+ function onMqlChange ( ) { setFromSystem ( ) ; }
784+ try { mq . addEventListener ( 'change' , onMqlChange ) ; } catch ( _ ) { }
785+ }
786+ }
787+
788+ themeSelect ?. addEventListener ( 'change' , ( ) => {
789+ const mode = themeSelect . value || 'system' ;
790+ try { localStorage . setItem ( LS_THEME , mode ) ; } catch ( _ ) { }
791+ applyTheme ( mode ) ;
792+ } ) ;
793+
762794 function getSelected ( groupedItems ) {
763795 const sels = [ ] ;
764796 document . querySelectorAll ( '.row-select:checked' ) . forEach ( cb => {
0 commit comments