1+ {{ $url := .Get "url" | default "#" }}
2+ {{ $title := .Get "title" | default "Visit Website" }}
3+ {{ $time := .Get "time" | default 5 }}
4+ {{/* Generate a unique ID for each modal on the page */}}
5+ {{ $modalId := printf "lb-modal-%d" (math.Counter) }}
6+
7+ < button class ="lb-btn " data-modal-target ="#{{ $modalId }} ">
8+ < svg xmlns ="http://www.w3.org/2000/svg " width ="16 " height ="16 " fill ="currentColor " viewBox ="0 0 16 16 ">
9+ < path fill-rule ="evenodd " d ="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5-.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z "/>
10+ < path fill-rule ="evenodd " d ="M16 1.5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 2.707V6.5a.5.5 0 0 0 1 0v-5z "/>
11+ </ svg >
12+ {{ $title }}
13+ </ button >
14+
15+ < div class ="lb-modal-overlay " id ="{{ $modalId }} " data-url ="{{ $url }} " data-time ="{{ $time }} ">
16+ < div class ="lb-modal-content ">
17+ < h2 class ="lb-modal-title "> {{ $title }}</ h2 >
18+ < p > Redirecting you to the destination...</ p >
19+ < div class ="lb-timer-wrapper ">
20+ < svg class ="lb-timer-svg " width ="120 " height ="120 " viewBox ="0 0 120 120 ">
21+ < circle class ="lb-timer-bg " cx ="60 " cy ="60 " r ="54 " />
22+ < circle class ="lb-timer-progress " cx ="60 " cy ="60 " r ="54 " />
23+ </ svg >
24+ < span class ="lb-timer-text "> {{ $time }}</ span >
25+ </ div >
26+ < button class ="lb-modal-close " aria-label ="Close modal "> ×</ button >
27+ </ div >
28+ </ div >
29+
30+
31+ < style >
32+ /* assets/css/link-button.css */
33+
34+ /* --- Variables for easy customization --- */
35+ : root {
36+ --lb-primary-color : # 28a745 ; /* Green for go/link */
37+ --lb-primary-hover : # 218838 ;
38+ --lb-light-gray : # f0f0f0 ;
39+ --lb-dark-gray : # 4a4a4a ;
40+ --lb-modal-bg : # ffffff ;
41+ --lb-overlay-bg : rgba (0 , 0 , 0 , 0.65 );
42+ }
43+
44+ /* --- The Link Button --- */
45+ .lb-btn {
46+ display : flex;
47+ align-items : center;
48+ gap : 8px ;
49+ padding : 12px 24px ;
50+ font-size : 16px ;
51+ font-weight : 600 ;
52+ color : white;
53+ background-color : var (--lb-primary-color );
54+ border : none;
55+ border-radius : 8px ;
56+ cursor : pointer;
57+ transition : background-color 0.3s ease, transform 0.2s ease;
58+ box-shadow : 0 4px 6px rgba (0 , 0 , 0 , 0.1 );
59+ margin-top : 1rem ;
60+ }
61+
62+ .lb-btn : hover {
63+ background-color : var (--lb-primary-hover );
64+ transform : translateY (-2px );
65+ }
66+
67+ /* --- The Modal --- */
68+ .lb-modal-overlay {
69+ position : fixed;
70+ top : 0 ;
71+ left : 0 ;
72+ width : 100% ;
73+ height : 100% ;
74+ background-color : var (--lb-overlay-bg );
75+ display : flex;
76+ justify-content : center;
77+ align-items : center;
78+ z-index : 1000 ;
79+ opacity : 0 ;
80+ visibility : hidden;
81+ transition : opacity 0.3s ease, visibility 0.3s ease;
82+ }
83+
84+ .lb-modal-overlay .active {
85+ opacity : 1 ;
86+ visibility : visible;
87+ }
88+
89+ .lb-modal-content {
90+ background-color : var (--lb-modal-bg );
91+ padding : 30px 40px ;
92+ border-radius : 12px ;
93+ box-shadow : 0 5px 20px rgba (0 , 0 , 0 , 0.2 );
94+ text-align : center;
95+ max-width : 400px ;
96+ width : 90% ;
97+ position : relative;
98+ transform : scale (0.9 );
99+ transition : transform 0.3s ease;
100+ }
101+
102+ .lb-modal-overlay .active .lb-modal-content {
103+ transform : scale (1 );
104+ }
105+
106+ .lb-modal-title {
107+ margin-top : 0 ;
108+ margin-bottom : 10px ;
109+ color : var (--lb-dark-gray );
110+ }
111+
112+ .lb-modal-content p {
113+ color : # 6c757d ;
114+ margin-bottom : 25px ;
115+ }
116+
117+ /* --- The Circular Timer --- */
118+ .lb-timer-wrapper {
119+ position : relative;
120+ width : 120px ;
121+ height : 120px ;
122+ margin : 0 auto;
123+ }
124+
125+ .lb-timer-svg {
126+ transform : rotate (-90deg ); /* Start animation from the top */
127+ }
128+
129+ .lb-timer-bg {
130+ fill : none;
131+ stroke : var (--lb-light-gray );
132+ stroke-width : 12 ;
133+ }
134+
135+ .lb-timer-progress {
136+ fill : none;
137+ stroke : var (--lb-primary-color );
138+ stroke-width : 12 ;
139+ stroke-linecap : round;
140+ /* Circumference = 2 * pi * r = 2 * 3.14159 * 54 = 339.29 */
141+ stroke-dasharray : 339.29 ;
142+ stroke-dashoffset : 339.29 ;
143+ transition : stroke-dashoffset 1s linear;
144+ }
145+
146+ .lb-timer-text {
147+ position : absolute;
148+ top : 50% ;
149+ left : 50% ;
150+ transform : translate (-50% , -50% );
151+ font-size : 36px ;
152+ font-weight : bold;
153+ color : var (--lb-primary-color );
154+ }
155+
156+ /* --- Close Button --- */
157+ .lb-modal-close {
158+ position : absolute;
159+ top : 10px ;
160+ right : 15px ;
161+ background : none;
162+ border : none;
163+ font-size : 28px ;
164+ color : # aaa ;
165+ cursor : pointer;
166+ transition : color 0.2s ease;
167+ }
168+
169+ .lb-modal-close : hover {
170+ color : # 333 ;
171+ }
172+ </ style >
173+
174+
175+ < script >
176+ // assets/js/link-button.js
177+ document . addEventListener ( 'DOMContentLoaded' , ( ) => {
178+ let timerInterval = null ;
179+
180+ const startTimer = ( duration , display , progressCircle , url ) => {
181+ let timer = duration ;
182+ const circumference = progressCircle . r . baseVal . value * 2 * Math . PI ;
183+ progressCircle . style . strokeDasharray = circumference ;
184+
185+ const updateTimer = ( ) => {
186+ display . textContent = timer ;
187+ // Calculate the stroke offset based on the time remaining
188+ const offset = circumference - ( timer / duration ) * circumference ;
189+ progressCircle . style . strokeDashoffset = offset ;
190+
191+ if ( -- timer < 0 ) {
192+ clearInterval ( timerInterval ) ;
193+ window . location . href = url ; // Redirect the user
194+ }
195+ } ;
196+
197+ updateTimer ( ) ; // Run once immediately
198+ timerInterval = setInterval ( updateTimer , 1000 ) ;
199+ } ;
200+
201+ const openModal = ( modal ) => {
202+ if ( ! modal ) return ;
203+ modal . classList . add ( 'active' ) ;
204+ const url = modal . dataset . url ;
205+ const time = parseInt ( modal . dataset . time , 10 ) ;
206+ const countdownDisplay = modal . querySelector ( '.lb-timer-text' ) ;
207+ const progressCircle = modal . querySelector ( '.lb-timer-progress' ) ;
208+
209+ clearInterval ( timerInterval ) ; // Clear any existing timers
210+ startTimer ( time , countdownDisplay , progressCircle , url ) ;
211+ } ;
212+
213+ const closeModal = ( modal ) => {
214+ if ( ! modal ) return ;
215+ modal . classList . remove ( 'active' ) ;
216+ clearInterval ( timerInterval ) ; // Stop timer if user closes manually
217+ } ;
218+
219+ // Event listener for all link buttons
220+ document . querySelectorAll ( '.lb-btn[data-modal-target]' ) . forEach ( button => {
221+ button . addEventListener ( 'click' , ( ) => {
222+ const modal = document . querySelector ( button . dataset . modalTarget ) ;
223+ openModal ( modal ) ;
224+ } ) ;
225+ } ) ;
226+
227+ // Event listener to close modal by clicking overlay
228+ document . querySelectorAll ( '.lb-modal-overlay' ) . forEach ( overlay => {
229+ overlay . addEventListener ( 'click' , ( e ) => {
230+ if ( e . target === overlay ) { // Ensure click is on overlay, not content
231+ closeModal ( overlay ) ;
232+ }
233+ } ) ;
234+ } ) ;
235+
236+ // Event listener for the 'X' close buttons
237+ document . querySelectorAll ( '.lb-modal-close' ) . forEach ( button => {
238+ button . addEventListener ( 'click' , ( ) => {
239+ const modal = button . closest ( '.lb-modal-overlay' ) ;
240+ closeModal ( modal ) ;
241+ } ) ;
242+ } ) ;
243+ } ) ;
244+ </ script >
0 commit comments