1- // Import statements
21import { snapdom } from '@zumer/snapdom' ;
32import { getMainElements } from './helpers/elements' ;
43import { isDevOptions , isLocalDevelopment } from './helpers/helpers' ;
54import { getAllPresets , getRandomPreset , setPreset } from './presets' ;
65
76/* ************** Elements ************** */
8- const { bannerImageContainer, bannerImage, toolbox } = getMainElements ( ) ;
7+
8+ const {
9+ bannerImageContainer,
10+ bannerImage,
11+ toolbox,
12+ } = getMainElements ( ) ;
913
1014/* ************** Options ************** */
15+
1116const initialTheme = {
1217 textAlign : "center" ,
1318 ...getAllPresets ( ) [ 15 ] ,
@@ -24,8 +29,10 @@ toolbox.querySelector('.size-inputs input#width-input').value = bannerImageConta
2429
2530document . addEventListener ( "DOMContentLoaded" , ( ) => {
2631 const theme = localStorage . getItem ( 'theme' ) ;
27- if ( theme ) setPreset ( JSON . parse ( theme ) , true ) ;
28- else setPreset ( initialTheme ) ;
32+ if ( theme )
33+ setPreset ( JSON . parse ( theme ) , true ) ;
34+ else
35+ setPreset ( initialTheme ) ;
2936} ) ;
3037
3138// Demo reset after ended
@@ -38,60 +45,185 @@ imgDecorationElement.className = 'img-decoration';
3845imgDecorationElement . style . position = 'absolute' ;
3946imgDecorationElement . style . bottom = 'calc(50%)' ;
4047imgDecorationElement . style . transform = 'translateY(50%)' ;
48+ imgDecorationElement . style . left = 'auto' ;
4149imgDecorationElement . style . right = '25px' ;
4250imgDecorationElement . style . width = '0px' ;
43- imgDecorationElement . alt = 'Header image decoration' ;
44- imageDecorationContainer . appendChild ( imgDecorationElement ) ;
45-
46- /* ==========================================================
47- 🆕 FEATURE: Preview Before Download
48- ========================================================== */
49- const previewButton = document . createElement ( 'button' ) ;
50- previewButton . className = 'preview-button' ;
51- previewButton . innerHTML = `<img src="./images/icons/preview.svg" width="20" /> Preview` ;
52- document . querySelector ( '.toolbox-buttons' ) . appendChild ( previewButton ) ;
53-
54- previewButton . addEventListener ( 'click' , async ( ) => {
55- try {
56- const png = await snapdom . toPng ( bannerImage , { embedFonts : true , scale : 1 } ) ;
57- const previewWindow = window . open ( '' , '_blank' ) ;
58- previewWindow . document . write ( '<title>Banner Preview</title>' ) ;
59- previewWindow . document . body . innerHTML = `<img src="${ png } " style="max-width:100%;display:block;margin:auto;">` ;
60- } catch ( error ) {
61- console . error ( 'Preview generation failed:' , error ) ;
62- showToast ( 'Preview generation failed 😞' , 'error' ) ;
51+ imgDecorationElement . alt = 'Header image decoration'
52+ imageDecorationContainer . appendChild ( imgDecorationElement )
53+
54+ /* ************** Header image options ************** */
55+
56+ // Download button
57+ document . querySelector ( '.download-button' )
58+ . addEventListener ( 'click' , async ( ) => {
59+ document . querySelector ( '.download-button img' ) . src = './images/icons/loading.gif'
60+
61+ try {
62+ await snapdom . download (
63+ bannerImage ,
64+ {
65+ embedFonts : true ,
66+ format : 'png' ,
67+ filename : 'github-header-banner' ,
68+ scale : 2
69+ } ) ;
70+ document . querySelector ( '.download-button img' ) . src = './images/icons/download.svg'
71+ showToast ( 'Banner downloaded successfully 🎉' , 'success' ) ;
72+ } catch ( error ) {
73+ console . error ( 'Image capture or download failed:' , error ) ;
74+ showToast ( 'Download failed 😞' , 'error' ) ;
75+ }
76+ } )
77+
78+ // For local development
79+ document . addEventListener ( "DOMContentLoaded" , ( event ) => {
80+ const displayButton = document . querySelector ( '.display-button' ) ;
81+ const miniatureButton = document . querySelector ( '.miniature-button' ) ;
82+ const testFontsTab = document . querySelector ( '.tablinks[data-name="test-fonts-section"]' ) ;
83+
84+ if ( isLocalDevelopment && isDevOptions == 1 ) {
85+ const el = document . querySelector ( '#github-header-image' ) ;
86+ const container = document . querySelector ( '.header-image-container' )
87+
88+ if ( displayButton ) {
89+ displayButton . style . display = "block" ;
90+
91+ displayButton . addEventListener ( 'click' , async ( ) => {
92+ const png = await snapdom . toPng ( el , { embedFonts : true } ) ;
93+
94+ const prevImage = container . children [ 1 ] ;
95+ if ( prevImage ) container . removeChild ( prevImage ) ;
96+
97+ container . appendChild ( png ) ;
98+ document . querySelector ( '.toolbox-container .toolbox-tools' ) . style . height = 'calc(100vh - 230px - 3rem - 35px - 1rem - 230px)'
99+ } )
100+ }
101+ if ( miniatureButton ) {
102+ miniatureButton . style . display = "block" ;
103+ // console.log('Running on localhost! display appending image option ...');
104+
105+ miniatureButton . addEventListener ( 'click' , async ( ) => {
106+ const png = await snapdom . toPng ( el , { embedFonts : true , scale : 0.25 } ) ;
107+
108+ const prevImage = container . children [ 1 ] ;
109+ if ( prevImage ) container . removeChild ( prevImage ) ;
110+
111+ container . appendChild ( png ) ;
112+ document . querySelector ( '.toolbox-container .toolbox-tools' ) . style . height = 'calc(100vh - 230px - 3rem - 35px - 1rem - 46px)'
113+ } )
114+ }
115+ if ( testFontsTab ) {
116+ // testFontsTab.style.display = "block"
117+ }
63118 }
64119} ) ;
65120
66- /* ==========================================================
67- 🆕 FEATURE: Auto-Save Theme Changes
68- ========================================================== */
69- // Every time user updates a setting in toolbox, we auto-save
70- toolbox . addEventListener ( 'input' , ( ) => {
71- const theme = localStorage . getItem ( 'theme' ) ;
72- if ( theme ) {
73- localStorage . setItem ( 'theme' , theme ) ;
74- showToast ( 'Theme auto-saved ✅' , 'success' ) ;
121+ // Toogle Dark Mode button
122+ document . querySelector ( '.dark-mode-button' )
123+ . addEventListener ( 'click' , ( e ) => {
124+ let resultBox = document . querySelector ( '.result-box' ) ;
125+ const toogleDarkModeButton = document . querySelector ( '.dark-mode-button' ) ;
126+ const toogleRandomizeButton = document . querySelector ( '.randomize-button' ) ;
127+ const toogleResetButton = document . querySelector ( '.reset-button' ) ;
128+ const toogleDownloadButton = document . querySelector ( '.download-button' ) ;
129+
130+ const size = 20 ;
131+
132+ resultBox . classList . toggle ( 'light-mode' ) ;
133+ if ( resultBox . className . includes ( 'light' ) ) {
134+ toogleDarkModeButton . innerHTML = `<img src="./images/icons/light-dark-black.svg" width="${ size } " />Light`
135+ toogleRandomizeButton . innerHTML = `<img src="./images/icons/random-black.svg" width="${ size } " />Random`
136+ toogleResetButton . innerHTML = `<img src="./images/icons/reset-black.svg" width="${ size } " />Reset`
137+ toogleDownloadButton . innerHTML = `<img src="./images/icons/download.svg" width="${ size } " />Download`
138+ } else {
139+ toogleDarkModeButton . innerHTML = `<img src="./images/icons/light-dark.svg" width="${ size } " />Dark`
140+ toogleRandomizeButton . innerHTML = `<img src="./images/icons/random.svg" width="${ size } " />Random`
141+ toogleResetButton . innerHTML = `<img src="./images/icons/reset.svg" width="${ size } " />Reset`
142+ toogleDownloadButton . innerHTML = `<img src="./images/icons/download.svg" width="${ size } " />Download`
143+ }
144+ } ) ;
145+
146+ // Randomize
147+ document . querySelector ( '.randomize-button' )
148+ . addEventListener ( 'click' , ( e ) => {
149+ const theme = getRandomPreset ( ) ;
150+ setPreset ( theme ) ;
151+ } ) ;
152+
153+ document . querySelector ( '.reset-button' )
154+ . addEventListener ( 'click' , ( e ) => {
155+ const darkMode = localStorage . getItem ( 'darkMode' ) ;
156+ localStorage . clear ( ) ;
157+ localStorage . setItem ( 'darkMode' , darkMode ) ;
158+ setPreset ( initialTheme ) ;
159+ } ) ;
160+
161+ /* ************** Tabs ************** */
162+
163+ function openTab ( e , name ) {
164+ let i , tabcontent , tablinks ;
165+
166+ tabcontent = document . getElementsByClassName ( "tabcontent" ) ;
167+ for ( i = 0 ; i < tabcontent . length ; i ++ ) {
168+ tabcontent [ i ] . style . display = "none" ;
75169 }
76- } ) ;
77170
78- /* ==========================================================
79- 🆕 FEATURE: Keyboard Shortcuts
80- ========================================================== */
81- document . addEventListener ( 'keydown' , ( e ) => {
82- if ( e . ctrlKey && e . key . toLowerCase ( ) === 'r' ) {
83- e . preventDefault ( ) ;
84- document . querySelector ( '.randomize-button' ) . click ( ) ;
171+ tablinks = document . getElementsByClassName ( "tablinks" ) ;
172+ for ( i = 0 ; i < tablinks . length ; i ++ ) {
173+ tablinks [ i ] . className = tablinks [ i ] . className . replace ( " active" , "" ) ;
85174 }
86- if ( e . ctrlKey && e . key . toLowerCase ( ) === 'd' ) {
87- e . preventDefault ( ) ;
88- document . querySelector ( '.download-button' ) . click ( ) ;
175+
176+ document . getElementById ( name ) . style . display = "block" ;
177+ e . currentTarget . className += " active" ;
178+ }
179+
180+ document . querySelectorAll ( '.tab .tablinks' )
181+ . forEach ( button => {
182+ button . addEventListener ( 'click' , ( e ) => {
183+ const name = e . target . getAttribute ( 'data-name' ) ;
184+ localStorage . setItem ( 'openTab' , name )
185+ openTab ( e , name ) ;
186+ } ) ;
187+ } )
188+
189+ // Saved tab
190+ document . addEventListener ( "DOMContentLoaded" , ( event ) => {
191+ const openTab = localStorage . getItem ( 'openTab' ) ;
192+ if ( openTab ) {
193+ document . querySelector ( `[data-name="${ openTab } "]` ) . click ( ) ;
194+ } else {
195+ document . getElementById ( "defaultOpenTag" ) . click ( ) ;
196+ }
197+ } ) ;
198+
199+ /* ************** Dark Mode ************** */
200+
201+ function setLightMode ( ) {
202+ localStorage . setItem ( 'darkMode' , 0 ) ;
203+ document . documentElement . setAttribute ( "data-theme" , "light" ) ;
204+ document . querySelector ( '#light-mode-btn' ) . classList . add ( 'selected' ) ;
205+ document . querySelector ( '#dark-mode-btn' ) . classList . remove ( 'selected' ) ;
206+ }
207+ function setDarkMode ( ) {
208+ localStorage . setItem ( 'darkMode' , 1 ) ;
209+ document . documentElement . setAttribute ( "data-theme" , "dark" ) ;
210+ document . querySelector ( '#light-mode-btn' ) . classList . remove ( 'selected' ) ;
211+ document . querySelector ( '#dark-mode-btn' ) . classList . add ( 'selected' ) ;
212+ }
213+
214+ document . addEventListener ( "DOMContentLoaded" , ( event ) => {
215+ const localDarkMode = localStorage . getItem ( 'darkMode' ) ;
216+ if ( localDarkMode && localDarkMode == 1 ) {
217+ document . querySelector ( '#dark-mode-btn' ) . classList . add ( 'selected' ) ;
218+ } else {
219+ document . querySelector ( '#light-mode-btn' ) . classList . add ( 'selected' ) ;
89220 }
221+ document . querySelector ( '#light-mode-btn' ) . onclick = setLightMode ;
90222} ) ;
91223
92- /* ==========================================================
93- 🆕 FEATURE: Notification Toasts
94- ========================================================== */
224+
225+ /* ************** Notification Toasts ************** */
226+
95227function showToast ( message , type = 'info' ) {
96228 const toast = document . createElement ( 'div' ) ;
97229 toast . className = `toast ${ type } ` ;
@@ -101,48 +233,5 @@ function showToast(message, type = 'info') {
101233 setTimeout ( ( ) => {
102234 toast . style . opacity = 0 ;
103235 setTimeout ( ( ) => toast . remove ( ) , 500 ) ;
104- } , 2000 ) ;
236+ } , 3000 ) ;
105237}
106-
107- // Add basic CSS for toasts dynamically
108- const style = document . createElement ( 'style' ) ;
109- style . textContent = `
110- .toast {
111- position: fixed;
112- bottom: 20px;
113- right: 20px;
114- background: #333;
115- color: white;
116- padding: 10px 15px;
117- border-radius: 6px;
118- font-size: 14px;
119- transition: opacity 0.5s;
120- z-index: 9999;
121- }
122- .toast.success { background: #4CAF50; }
123- .toast.error { background: #E53935; }
124- ` ;
125- document . head . appendChild ( style ) ;
126-
127- /* ==========================================================
128- EXISTING DOWNLOAD FUNCTIONALITY
129- ========================================================== */
130- document . querySelector ( '.download-button' )
131- . addEventListener ( 'click' , async ( ) => {
132- document . querySelector ( '.download-button img' ) . src = './images/icons/loading.gif' ;
133- try {
134- await snapdom . download ( bannerImage , {
135- embedFonts : true ,
136- format : 'png' ,
137- filename : 'github-header-banner' ,
138- scale : 2
139- } ) ;
140- document . querySelector ( '.download-button img' ) . src = './images/icons/download.svg' ;
141- showToast ( 'Banner downloaded successfully 🎉' , 'success' ) ;
142- } catch ( error ) {
143- console . error ( 'Image capture or download failed:' , error ) ;
144- showToast ( 'Download failed ❌' , 'error' ) ;
145- }
146- } ) ;
147-
148- // (Rest of your existing code remains unchanged)
0 commit comments