11<!DOCTYPE html>
22< html lang ="en ">
33< head >
4- < script > fetch ( 'https://api.countapi.xyz/hit/rmkr-dev.github.io/time' ) ; </ script >
54 < meta charset ="UTF-8 ">
65 < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
76 < title > Global Time Sync | RMKR Dev</ title >
87
9- < link rel ="icon " type ="image/svg+xml " href ="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%23FFC300' d='M256 0a256 256 0 1 1 0 512A256 256 0 1 1 256 0zM232 120V256c0 8 4 15.5 10.7 20l96 64c11 7.4 25.9 4.4 33.3-6.7s4.4-25.9-6.7-33.3L280 243.2V120c0-13.3-10.7-24-24-24s-24 10.7-24 24z'/%3E%3C/svg%3E ">
108 < script src ="https://cdn.tailwindcss.com "> </ script >
119 < link href ="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap " rel ="stylesheet ">
1210 < link rel ="stylesheet " href ="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css " />
2018 body { font-family : 'Inter' , sans-serif; background-color : var (--color-bg ); color : var (--color-text ); }
2119 .wrap { max-width : 1200px ; margin : 0 auto; padding : 2rem ; }
2220
23- /* Timeline Row Styling */
2421 .timeline-row {
25- background : var (--color-card );
26- border : 1px solid var (--color-line );
27- border-radius : 12px ;
28- padding : 1rem 1.5rem ;
29- margin-bottom : 0.5rem ;
30- display : flex;
31- align-items : center;
32- gap : 20px ;
22+ background : var (--color-card ); border : 1px solid var (--color-line );
23+ border-radius : 12px ; padding : 1rem 1.5rem ; margin-bottom : 0.5rem ;
24+ display : flex; align-items : center; gap : 20px ;
3325 }
3426
35- .tz-info { width : 240px ; flex-shrink : 0 ; border-right : 1px solid var (--color-line ); }
36-
27+ .tz-info { width : 220px ; flex-shrink : 0 ; border-right : 1px solid var (--color-line ); }
3728 .grid-viewport { flex-grow : 1 ; overflow-x : auto; scrollbar-width : none; }
38- .grid-viewport ::-webkit-scrollbar { display : none; }
39-
4029 .hour-grid { display : grid; grid-template-columns : repeat (24 , 42px ); gap : 4px ; }
4130
4231 .hour-cell {
4332 height : 48px ; background : rgba (255 , 255 , 255 , 0.03 );
44- border : 1px solid rgba (255 , 255 , 255 , 0.08 );
45- border-radius : 6px ; display : flex; flex-direction : column;
46- align-items : center; justify-content : center; font-size : 0.7rem ;
47- cursor : pointer; transition : all 0.2s ;
33+ border : 1px solid rgba (255 , 255 , 255 , 0.08 ); border-radius : 6px ;
34+ display : flex; flex-direction : column; align-items : center; justify-content : center;
35+ font-size : 0.7rem ; cursor : pointer; transition : all 0.2s ;
4836 }
4937
5038 .hour-cell .active { background : var (--color-accent ) !important ; color : var (--color-bg ) !important ; font-weight : 800 ; transform : scale (1.05 ); z-index : 10 ; }
5139 .hour-cell .work { border-bottom : 3px solid # 4ade80 ; }
52- .hour-cell .night { opacity : 0.4 ; background : rgba (0 , 0 , 0 , 0.2 ); }
40+ .hour-cell .night { opacity : 0.3 ; background : rgba (0 , 0 , 0 , 0.3 ); }
5341
54- /* Custom Dropdown/Search */
55- .search-container { position : relative; width : 350px ; }
56- # tz-input {
57- background : # 0C1524 ; color : white; border : 1px solid var (--color-line );
58- padding : 12px 18px ; border-radius : 10px ; width : 100% ; outline : none;
59- }
60- # tz-list {
61- position : absolute; top : 110% ; left : 0 ; width : 100% ; max-height : 300px ;
62- background : # 1e293b ; border : 1px solid var (--color-line ); border-radius : 10px ;
63- overflow-y : auto; z-index : 100 ; display : none; box-shadow : 0 10px 25px rgba (0 , 0 , 0 , 0.5 );
42+ .quick-tag {
43+ background : var (--color-line ); color : var (--color-text );
44+ padding : 4px 10px ; border-radius : 6px ; font-size : 0.65rem ;
45+ font-weight : 800 ; cursor : pointer; transition : 0.2s ;
6446 }
65- .tz-option { padding : 10px 15px ; cursor : pointer; font-size : 0.85rem ; border-bottom : 1px solid rgba (255 , 255 , 255 , 0.05 ); }
66- .tz-option : hover { background : var (--color-accent ); color : var (--color-bg ); font-weight : bold; }
47+ .quick-tag : hover { background : var (--color-accent ); color : var (--color-bg ); }
6748 </ style >
6849</ head >
6950< body >
7051
7152< div class ="wrap ">
72- < header class ="flex justify-between items-center mb-10 ">
53+ < header class ="flex justify-between items-center mb-8 ">
7354 < div >
74- < h1 class ="text-3xl font-black text-white italic "> TIME< span class ="text-[--color-accent] not-italic "> SYNC</ span > </ h1 >
75- < p class ="text-[10px ] text-[--color-muted] font-bold tracking-[0.2em] mt-1 uppercase " > Principal Engineering Toolkit </ p >
55+ < h1 class ="text-2xl font-black text-white italic tracking-tighter "> TIME< span class ="text-[--color-accent] not-italic "> SYNC</ span > </ h1 >
56+ < p class ="text-[9px ] text-[--color-muted] font-bold tracking-[0.2em] uppercase mt-1 " > Global Shift Alignment </ p >
7657 </ div >
7758 < a href ="../ " class ="bg-[--color-card] w-10 h-10 flex items-center justify-center rounded-xl border border-[--color-line] hover:border-[--color-accent] transition ">
7859 < i class ="fa-solid fa-house-user "> </ i >
7960 </ a >
8061 </ header >
8162
82- < div class ="bg-[--color-card] p-6 rounded-2xl mb-8 border border-[--color-line] flex flex-wrap gap-6 items-center ">
83- < div class ="search-container ">
84- < span class ="text-[10px] font-black text-[--color-muted] uppercase tracking-widest ml-1 mb-2 block "> Search City / Region</ span >
85- < input type ="text " id ="tz-input " placeholder ="Start typing (e.g. New York, Tokyo...) " onfocus ="showList() " oninput ="filterList() ">
86- < div id ="tz-list "> </ div >
87- </ div >
88-
89- < div class ="ml-auto flex items-center gap-8 ">
90- < div class ="text-right border-r border-[--color-line] pr-8 ">
91- < p class ="text-[10px] uppercase text-[--color-muted] font-bold mb-1 "> Internal Reference</ p >
92- < p id ="utc-clock " class ="font-mono text-xl text-white font-black "> 00:00 < span class ="text-[--color-accent] text-xs "> UTC</ span > </ p >
63+ < div class ="bg-[--color-card] p-6 rounded-2xl mb-8 border border-[--color-line] ">
64+ < div class ="flex flex-wrap items-center gap-6 ">
65+ < div class ="flex-grow ">
66+ < span class ="text-[10px] font-black text-[--color-muted] uppercase tracking-widest mb-3 block "> Quick Add Standards</ span >
67+ < div class ="flex flex-wrap gap-2 ">
68+ < button onclick ="addByCode('PST', 'America/Los_Angeles') " class ="quick-tag "> PST / PDT</ button >
69+ < button onclick ="addByCode('MST', 'America/Denver') " class ="quick-tag "> MST / MDT</ button >
70+ < button onclick ="addByCode('CST', 'America/Chicago') " class ="quick-tag "> CST / CDT</ button >
71+ < button onclick ="addByCode('EST', 'America/New_York') " class ="quick-tag "> EST / EDT</ button >
72+
73+ < button onclick ="addByCode('BRT', 'America/Sao_Paulo') " class ="quick-tag "> BRT (Brazil)</ button >
74+
75+ < button onclick ="addByCode('UTC', 'UTC') " class ="quick-tag "> UTC / GMT</ button >
76+ < button onclick ="addByCode('BST', 'Europe/London') " class ="quick-tag "> London</ button >
77+ < button onclick ="addByCode('CET', 'Europe/Paris') " class ="quick-tag "> CET (Europe)</ button >
78+ < button onclick ="addByCode('EET', 'Europe/Istanbul') " class ="quick-tag "> EET (EE/Turkey)</ button >
79+
80+ < button onclick ="addByCode('IST', 'Asia/Kolkata') " class ="quick-tag "> IST (India)</ button >
81+ < button onclick ="addByCode('SGT', 'Asia/Singapore') " class ="quick-tag "> SGT / HKG</ button >
82+ < button onclick ="addByCode('JST', 'Asia/Tokyo') " class ="quick-tag "> JST (Japan)</ button >
83+ < button onclick ="addByCode('AEST', 'Australia/Sydney') " class ="quick-tag "> AEST (Sydney)</ button >
84+ </ div >
85+ </ div >
86+
87+ < div class ="flex items-center gap-6 border-l border-[--color-line] pl-6 ">
88+ < div class ="text-right ">
89+ < p class ="text-[9px] uppercase text-[--color-muted] font-bold "> Ref Time</ p >
90+ < p id ="utc-clock " class ="font-mono text-xl text-white font-black "> 00:00 < span class ="text-[--color-accent] text-xs "> UTC</ span > </ p >
91+ </ div >
92+ < button onclick ="resetToNow() " class ="text-[10px] font-black text-[--color-accent] border-2 border-[--color-accent] px-4 py-2 rounded-lg hover:bg-[--color-accent] hover:text-[--color-bg] transition-all "> NOW</ button >
9393 </ div >
94- < button onclick ="resetToNow() " class ="text-[10px] font-black text-[--color-accent] border-2 border-[--color-accent] px-4 py-2 rounded-lg hover:bg-[--color-accent] hover:text-[--color-bg] transition-all uppercase "> Sync to Now</ button >
9594 </ div >
9695 </ div >
9796
@@ -100,45 +99,18 @@ <h1 class="text-3xl font-black text-white italic">TIME<span class="text-[--color
10099
101100< script >
102101 let activeUtcIndex = new Date ( ) . getUTCHours ( ) ;
102+ // Default: Local + UTC
103103 const localTZ = Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone ;
104- let selectedZones = [ localTZ ] ;
105- const allZones = Intl . supportedValuesOf ( 'timeZone' ) ;
106-
107- // Setup Custom Search List
108- const input = document . getElementById ( 'tz-input' ) ;
109- const list = document . getElementById ( 'tz-list' ) ;
110-
111- function showList ( ) { list . style . display = 'block' ; filterList ( ) ; }
112-
113- // Hide list when clicking outside
114- document . addEventListener ( 'click' , ( e ) => {
115- if ( ! e . target . closest ( '.search-container' ) ) list . style . display = 'none' ;
116- } ) ;
117-
118- function filterList ( ) {
119- const filter = input . value . toLowerCase ( ) ;
120- list . innerHTML = '' ;
121- const filtered = allZones . filter ( z => z . toLowerCase ( ) . includes ( filter ) ) ;
122-
123- filtered . forEach ( zone => {
124- const div = document . createElement ( 'div' ) ;
125- div . className = 'tz-option' ;
126- div . innerText = zone . replace ( / _ / g, ' ' ) ;
127- div . onclick = ( ) => {
128- if ( ! selectedZones . includes ( zone ) ) {
129- selectedZones . push ( zone ) ;
130- render ( ) ;
131- }
132- input . value = '' ;
133- list . style . display = 'none' ;
134- } ;
135- list . appendChild ( div ) ;
136- } ) ;
137- }
138-
139- function updateUTC ( ) {
140- const now = new Date ( ) ;
141- document . getElementById ( 'utc-clock' ) . innerHTML = `${ now . getUTCHours ( ) . toString ( ) . padStart ( 2 , '0' ) } :${ now . getUTCMinutes ( ) . toString ( ) . padStart ( 2 , '0' ) } <span class="text-[--color-accent] text-xs">UTC</span>` ;
104+ let selectedZones = [
105+ { label : 'LOCAL' , zone : localTZ } ,
106+ { label : 'UTC' , zone : 'UTC' }
107+ ] ;
108+
109+ function addByCode ( label , zone ) {
110+ if ( ! selectedZones . find ( z => z . label === label ) ) {
111+ selectedZones . push ( { label, zone } ) ;
112+ render ( ) ;
113+ }
142114 }
143115
144116 function removeZone ( index ) {
@@ -147,40 +119,43 @@ <h1 class="text-3xl font-black text-white italic">TIME<span class="text-[--color
147119
148120 function resetToNow ( ) { activeUtcIndex = new Date ( ) . getUTCHours ( ) ; render ( ) ; }
149121
122+ function updateUTC ( ) {
123+ const now = new Date ( ) ;
124+ document . getElementById ( 'utc-clock' ) . innerHTML = `${ now . getUTCHours ( ) . toString ( ) . padStart ( 2 , '0' ) } :${ now . getUTCMinutes ( ) . toString ( ) . padStart ( 2 , '0' ) } <span class="text-[--color-accent] text-xs">UTC</span>` ;
125+ }
126+
150127 function render ( ) {
151128 const container = document . getElementById ( 'timeline-container' ) ;
152129 container . innerHTML = '' ;
153130
154- selectedZones . forEach ( ( zone , idx ) => {
131+ selectedZones . forEach ( ( obj , idx ) => {
155132 const row = document . createElement ( 'div' ) ;
156133 row . className = 'timeline-row' ;
157134 const now = new Date ( ) ;
158- const timeInZone = now . toLocaleTimeString ( 'en-US' , { timeZone : zone , hour : '2-digit' , minute : '2-digit' , hour12 : true } ) ;
159- const offsetName = new Intl . DateTimeFormat ( 'en-US' , { timeZone : zone , timeZoneName :'short' } ) . formatToParts ( now ) . find ( p => p . type === 'timeZoneName' ) . value ;
135+ const timeInZone = now . toLocaleTimeString ( 'en-US' , { timeZone : obj . zone , hour : '2-digit' , minute : '2-digit' , hour12 : true } ) ;
160136
161137 row . innerHTML = `
162138 <div class="tz-info">
163139 <div class="flex justify-between items-center mb-1 pr-4">
164- <span class="font-black text-white text-sm tracking-tight">${ zone . split ( '/' ) . pop ( ) . replace ( / _ / g , ' ' ) } </span>
140+ <span class="font-black text-white text-sm tracking-tight">${ obj . label } </span>
165141 <span class="text-[11px] font-mono text-[--color-accent] font-bold">${ timeInZone } </span>
166142 </div>
167143 <div class="flex justify-between items-center pr-4">
168- <span class="text-[9px ] text-[--color-muted] font-bold uppercase tracking-tighter ">${ offsetName } </span>
169- ${ idx !== 0 ? `<button onclick="removeZone(${ idx } )" class="text-[9px] font-black text-red-400/50 hover:text-red-400 uppercase">Delete </button>` : `<span class="text-[9px ] text-blue-400 font-black uppercase">Local </span>` }
144+ <span class="text-[8px ] text-[--color-muted] font-bold uppercase truncate max-w-[120px] ">${ obj . zone } </span>
145+ ${ idx > 1 ? `<button onclick="removeZone(${ idx } )" class="text-[9px] font-black text-red-400/50 hover:text-red-400 uppercase">Del </button>` : `<span class="text-[8px ] text-blue-400/40 font-black uppercase">Fixed </span>` }
170146 </div>
171147 </div>
172- <div class="grid-viewport"><div class="hour-grid" id="grid- ${ idx } " ></div></div>
148+ <div class="grid-viewport"><div class="hour-grid"></div></div>
173149 ` ;
174150
175151 const grid = row . querySelector ( '.hour-grid' ) ;
176152 for ( let i = 0 ; i < 24 ; i ++ ) {
177153 const cell = document . createElement ( 'div' ) ;
178154 const d = new Date ( ) ; d . setUTCHours ( i , 0 , 0 , 0 ) ;
179- const localHour = parseInt ( d . toLocaleTimeString ( 'en-US' , { timeZone : zone , hour12 : false , hour : 'numeric' } ) ) ;
180- const ampm = d . toLocaleTimeString ( 'en-US' , { timeZone : zone , hour : 'numeric' , hour12 : true } ) . split ( ' ' ) [ 1 ] ;
181- const isActive = i === activeUtcIndex ;
155+ const localHour = parseInt ( d . toLocaleTimeString ( 'en-US' , { timeZone : obj . zone , hour12 : false , hour : 'numeric' } ) ) ;
156+ const ampm = d . toLocaleTimeString ( 'en-US' , { timeZone : obj . zone , hour : 'numeric' , hour12 : true } ) . split ( ' ' ) [ 1 ] ;
182157
183- cell . className = `hour-cell ${ localHour >= 9 && localHour <= 17 ? 'work' : '' } ${ localHour >= 22 || localHour <= 6 ? 'night' : '' } ${ isActive ? 'active' : '' } ` ;
158+ cell . className = `hour-cell ${ localHour >= 9 && localHour <= 17 ? 'work' : '' } ${ localHour >= 22 || localHour <= 6 ? 'night' : '' } ${ i === activeUtcIndex ? 'active' : '' } ` ;
184159 cell . innerHTML = `<span class="text-xs font-bold">${ localHour % 12 || 12 } </span><span class="text-[7px] font-black uppercase opacity-60">${ ampm } </span>` ;
185160 cell . onclick = ( ) => { activeUtcIndex = i ; render ( ) ; } ;
186161 grid . appendChild ( cell ) ;
0 commit comments