|
1 | 1 | <!DOCTYPE html> |
2 | 2 | <html lang="fr"> |
3 | 3 | <head> |
4 | | -<meta charset="UTF-8"> |
5 | | -<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
6 | | -<title>Timestamp Discord</title> |
| 4 | +<meta charset="UTF‑8"> |
| 5 | +<meta name="viewport" content="width=device‑width, initial‑scale=1.0"> |
| 6 | +<title>Timestamp Discord Style r.3v.fi</title> |
7 | 7 | <style> |
8 | | - :root { |
9 | | - --primary-bg: linear-gradient(145deg, #2b2b3f, #3a3a57); |
10 | | - --body-bg: linear-gradient(135deg, #1f1f2e, #2a2a3f); |
11 | | - --button-bg: linear-gradient(90deg, #ff6a88, #ff99ac); |
12 | | - --button-hover-bg: linear-gradient(90deg, #ff99ac, #ff6a88); |
13 | | - --toast-bg: linear-gradient(90deg, #22c55e, #4ade80); |
14 | | - --font-main: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
15 | | - } |
16 | | - |
17 | 8 | body { |
18 | | - margin: 0; |
19 | | - font-family: var(--font-main); |
20 | | - background: var(--body-bg); |
| 9 | + font-family: Arial, sans-serif; |
| 10 | + background: #1a1a2e; |
| 11 | + color: white; |
21 | 12 | display: flex; |
22 | | - justify-content: center; |
| 13 | + flex-direction: column; |
23 | 14 | align-items: center; |
24 | | - min-height: 100vh; |
25 | | - color: white; |
| 15 | + padding: 2rem; |
26 | 16 | } |
27 | 17 |
|
28 | 18 | .container { |
29 | | - background: var(--primary-bg); |
| 19 | + background: #22223b; |
30 | 20 | padding: 2rem; |
31 | | - border-radius: 1.5rem; |
32 | | - box-shadow: 0 10px 30px rgba(0,0,0,0.5); |
| 21 | + border-radius: 1rem; |
33 | 22 | width: 100%; |
34 | | - max-width: 400px; |
35 | | - text-align: center; |
| 23 | + max-width: 450px; |
36 | 24 | } |
37 | 25 |
|
38 | | - h1 { margin-bottom: 1rem; } |
| 26 | + h1 { text-align: center; margin-bottom: 1rem; } |
39 | 27 |
|
40 | | - button { |
41 | | - cursor: pointer; |
42 | | - border: none; |
43 | | - border-radius: 0.75rem; |
44 | | - padding: 0.5rem 1rem; |
45 | | - font-weight: bold; |
46 | | - background: var(--button-bg); |
47 | | - color: white; |
48 | | - transition: all 0.3s; |
49 | | - margin-top: 1rem; |
| 28 | + /* Calendrier */ |
| 29 | + .calendar { |
| 30 | + display: grid; |
| 31 | + grid-template-columns: repeat(7, 1fr); |
| 32 | + gap: 5px; |
| 33 | + margin-bottom: 1rem; |
50 | 34 | } |
51 | | - button:hover { background: var(--button-hover-bg); transform: translateY(-2px); } |
52 | 35 |
|
53 | | - #result { |
54 | | - margin-top: 1rem; |
55 | | - width: 100%; |
56 | | - padding: 0.5rem; |
57 | | - border-radius: 0.75rem; |
58 | | - background: #3b3b55; |
59 | | - font-family: monospace; |
| 36 | + .calendar div { |
| 37 | + padding: 8px; |
60 | 38 | text-align: center; |
| 39 | + cursor: pointer; |
| 40 | + background: #362e6d; |
| 41 | + border-radius: 6px; |
| 42 | + transition: 0.2s; |
61 | 43 | } |
| 44 | + .calendar div:hover { background: #4a47a3; } |
| 45 | + .calendar .selected { background: #ff6b6b; } |
62 | 46 |
|
63 | | - /* --- TOASTS --- */ |
64 | | - #toast-container { position: fixed; bottom: 2rem; right: 2rem; display: flex; flex-direction: column-reverse; gap: 0.5rem; z-index:1000;} |
65 | | - .toast { position:relative; overflow:hidden; min-width:200px; padding:1rem; border-radius:.75rem; background:var(--toast-bg); opacity:0; transform:translateY(20px); transition:opacity .3s, transform .3s;} |
66 | | - .toast.show { opacity:1; transform:translateY(0);} |
67 | | - .toast .progress { position:absolute; bottom:0; left:0; height:4px; background:white; width:100%; transform-origin:right; animation: shrink 5s linear forwards;} |
68 | | - @keyframes shrink { from {transform:scaleX(1);} to {transform:scaleX(0);} } |
69 | | - |
70 | | - /* --- DATE PICKER STYLE --- */ |
71 | | - .calendar { display:grid; grid-template-columns:repeat(7,1fr); gap:0.25rem; margin-bottom:1rem; } |
72 | | - .calendar div { padding:.5rem; background:#3b3b55; border-radius:.5rem; cursor:pointer; transition:.2s; } |
73 | | - .calendar div:hover { background:#5a5ac0; } |
74 | | - .calendar .selected { background:#ff6a88; } |
75 | | - |
76 | | - .month-nav { display:flex; justify-content:space-between; margin-bottom:0.5rem; } |
| 47 | + .nav { |
| 48 | + display: flex; |
| 49 | + justify-content: space-between; |
| 50 | + margin-bottom: 0.5rem; |
| 51 | + } |
| 52 | + .nav button { |
| 53 | + background: #4a47a3; |
| 54 | + border: none; |
| 55 | + padding: 4px 8px; |
| 56 | + border-radius: 6px; |
| 57 | + cursor: pointer; |
| 58 | + } |
77 | 59 |
|
78 | | - /* --- CLOCK STYLE --- */ |
| 60 | + /* Horloge */ |
79 | 61 | .clock { |
80 | | - position: relative; |
81 | | - width: 200px; height: 200px; |
82 | | - margin: 0 auto 1rem; |
| 62 | + width: 260px; |
| 63 | + height: 260px; |
| 64 | + border: 4px solid #4a47a3; |
83 | 65 | border-radius: 50%; |
84 | | - background:#3b3b55; |
| 66 | + position: relative; |
| 67 | + margin: auto; |
| 68 | + margin-bottom: 1rem; |
| 69 | + } |
| 70 | + .hourHand, .minuteHand { |
| 71 | + position: absolute; |
| 72 | + left: 50%; |
| 73 | + top: 50%; |
| 74 | + background: #ff6b6b; |
| 75 | + transform-origin: bottom; |
| 76 | + pointer-events: none; |
| 77 | + } |
| 78 | + .hourHand { width: 6px; height: 60px; } |
| 79 | + .minuteHand { width: 4px; height: 90px; background: #f7d794; } |
| 80 | + |
| 81 | + .clockNumbers { |
| 82 | + position: absolute; |
| 83 | + width: 100%; |
| 84 | + height: 100%; |
| 85 | + pointer-events: none; |
85 | 86 | } |
86 | | - .clock .hand { |
| 87 | + .clockNumbers div { |
87 | 88 | position: absolute; |
88 | | - width:2px; height:80px; background:white; |
89 | | - top:50%; left:50%; |
90 | | - transform-origin:bottom center; |
91 | | - transform:rotate(0deg) translateY(-50%); |
| 89 | + width: 20px; |
| 90 | + text-align: center; |
| 91 | + font-size: 14px; |
| 92 | + font-weight: bold; |
| 93 | + } |
| 94 | + |
| 95 | + /* Result */ |
| 96 | + #result { |
| 97 | + width: 100%; |
| 98 | + padding: 0.5rem; |
| 99 | + margin-bottom: 0.5rem; |
| 100 | + border-radius: 0.5rem; |
| 101 | + border: none; |
| 102 | + background: #362e6d; |
| 103 | + color: white; |
| 104 | + font-family: monospace; |
| 105 | + text-align: center; |
92 | 106 | } |
93 | | - .clock .center { width:10px; height:10px; background:white; border-radius:50%; position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);} |
94 | 107 | </style> |
95 | 108 | </head> |
96 | 109 | <body> |
97 | 110 |
|
98 | 111 | <div class="container"> |
99 | | - <h1>⏱ Discord Timestamp</h1> |
| 112 | + <h1>Discord Timestamp</h1> |
100 | 113 |
|
101 | | - <!-- DATE PICKER --> |
102 | | - <div class="month-nav"> |
103 | | - <button id="prev-month"><</button> |
104 | | - <span id="month-year"></span> |
105 | | - <button id="next-month">></button> |
| 114 | + <!-- Calendrier --> |
| 115 | + <div class="nav"> |
| 116 | + <button id="prevMonth"><</button> |
| 117 | + <span id="monthYear"></span> |
| 118 | + <button id="nextMonth">></button> |
106 | 119 | </div> |
107 | 120 | <div class="calendar" id="calendar"></div> |
108 | 121 |
|
109 | | - <!-- CLOCK PICKER --> |
| 122 | + <!-- Horloge --> |
110 | 123 | <div class="clock" id="clock"> |
111 | | - <div class="hand" id="hour-hand"></div> |
112 | | - <div class="center"></div> |
| 124 | + <div class="clockNumbers"></div> |
| 125 | + <div class="hourHand"></div> |
| 126 | + <div class="minuteHand"></div> |
113 | 127 | </div> |
114 | | - <input type="range" min="0" max="23" id="hour-range" value="12"> |
115 | 128 |
|
116 | 129 | <button onclick="generateTimestamp()">Générer</button> |
117 | | - <input id="result" type="text" readonly/> |
| 130 | + <input id="result" readonly> |
118 | 131 | </div> |
119 | 132 |
|
120 | | -<div id="toast-container"></div> |
121 | | - |
122 | 133 | <script> |
123 | 134 | let selectedDate = new Date(); |
124 | | -const calendarEl = document.getElementById('calendar'); |
125 | | -const monthYearEl = document.getElementById('month-year'); |
126 | | -const hourHand = document.getElementById('hour-hand'); |
127 | | -const hourRange = document.getElementById('hour-range'); |
| 135 | +let selectedHour = selectedDate.getHours(); |
| 136 | +let selectedMinute = selectedDate.getMinutes(); |
128 | 137 |
|
| 138 | +// Render calendar |
129 | 139 | function renderCalendar() { |
130 | | - calendarEl.innerHTML = ''; |
| 140 | + const cal = document.getElementById('calendar'); |
| 141 | + cal.innerHTML=''; |
131 | 142 | const year = selectedDate.getFullYear(); |
132 | 143 | const month = selectedDate.getMonth(); |
133 | 144 | const firstDay = new Date(year, month, 1).getDay(); |
134 | | - const daysInMonth = new Date(year, month+1,0).getDate(); |
135 | | - monthYearEl.textContent = selectedDate.toLocaleString('default',{month:'long'}) + ' ' + year; |
| 145 | + const daysInMonth = new Date(year, month+1, 0).getDate(); |
| 146 | + |
| 147 | + document.getElementById('monthYear').textContent = |
| 148 | + selectedDate.toLocaleString('default',{ month:'long', year:'numeric' }); |
136 | 149 |
|
137 | | - for(let i=0;i<firstDay;i++){calendarEl.innerHTML += '<div></div>';} |
| 150 | + for(let i=0;i<firstDay;i++) cal.innerHTML += '<div></div>'; |
138 | 151 | for(let d=1; d<=daysInMonth; d++){ |
139 | | - const div = document.createElement('div'); |
140 | | - div.textContent = d; |
141 | | - if(d===selectedDate.getDate()) div.classList.add('selected'); |
142 | | - div.addEventListener('click',()=>{selectedDate.setDate(d); renderCalendar();}); |
143 | | - calendarEl.appendChild(div); |
| 152 | + const cell = document.createElement('div'); |
| 153 | + cell.textContent = d; |
| 154 | + if(d === selectedDate.getDate()) cell.classList.add('selected'); |
| 155 | + cell.onclick = ()=>{ selectedDate.setDate(d); renderCalendar(); }; |
| 156 | + cal.appendChild(cell); |
144 | 157 | } |
145 | 158 | } |
146 | 159 |
|
147 | | -document.getElementById('prev-month').addEventListener('click',()=>{selectedDate.setMonth(selectedDate.getMonth()-1); renderCalendar();}); |
148 | | -document.getElementById('next-month').addEventListener('click',()=>{selectedDate.setMonth(selectedDate.getMonth()+1); renderCalendar();}); |
| 160 | +document.getElementById('prevMonth').onclick = ()=>{ selectedDate.setMonth(selectedDate.getMonth()-1); renderCalendar(); }; |
| 161 | +document.getElementById('nextMonth').onclick = ()=>{ selectedDate.setMonth(selectedDate.getMonth()+1); renderCalendar(); }; |
149 | 162 | renderCalendar(); |
150 | 163 |
|
151 | | -hourRange.addEventListener('input',(e)=>{ |
152 | | - const hour = e.target.value; |
153 | | - hourHand.style.transform = `rotate(${hour*15}deg) translateY(-50%)`; // simple rotation pour visuel |
154 | | -}); |
| 164 | +// Clock visuals |
| 165 | +const clock = document.getElementById('clock'); |
| 166 | +const hourHand = document.querySelector('.hourHand'); |
| 167 | +const minuteHand = document.querySelector('.minuteHand'); |
| 168 | +const clockNumbers = document.querySelector('.clockNumbers'); |
| 169 | + |
| 170 | +// place numbers |
| 171 | +for(let i=1; i<=12; i++){ |
| 172 | + const num = document.createElement('div'); |
| 173 | + const angle = (i/12)*360; |
| 174 | + const rad = Math.PI * angle/180; |
| 175 | + num.style.top = `${50 - Math.cos(rad)*40}%`; |
| 176 | + num.style.left= `${50 + Math.sin(rad)*40}%`; |
| 177 | + num.textContent = i; |
| 178 | + clockNumbers.appendChild(num); |
| 179 | +} |
155 | 180 |
|
156 | | -function generateTimestamp(){ |
157 | | - const date = new Date(selectedDate); |
158 | | - date.setHours(hourRange.value); |
159 | | - date.setMinutes(0); |
160 | | - const unix = Math.floor(date.getTime()/1000); |
| 181 | +function updateHands() { |
| 182 | + hourHand.style.transform = `rotate(${selectedHour*30 + selectedMinute*0.5}deg) translate(-50%,-100%)`; |
| 183 | + minuteHand.style.transform = `rotate(${selectedMinute*6}deg) translate(-50%,-100%)`; |
| 184 | +} |
| 185 | +updateHands(); |
| 186 | + |
| 187 | +// Click on clock to set time |
| 188 | +clock.onclick = (e) => { |
| 189 | + const rect = clock.getBoundingClientRect(); |
| 190 | + const x = e.clientX - (rect.left + rect.width/2); |
| 191 | + const y = e.clientY - (rect.top + rect.height/2); |
| 192 | + const angle = Math.atan2(y, x) * (180 / Math.PI) + 90; |
| 193 | + const normalized = (angle<0 ? angle+360 : angle); |
| 194 | + selectedHour = Math.floor(normalized / 30); |
| 195 | + selectedMinute = Math.floor((normalized % 30)*2); |
| 196 | + updateHands(); |
| 197 | +}; |
| 198 | + |
| 199 | +// Generate timestamp |
| 200 | +function generateTimestamp() { |
| 201 | + selectedDate.setHours(selectedHour); |
| 202 | + selectedDate.setMinutes(selectedMinute); |
| 203 | + const unix = Math.floor(selectedDate.getTime()/1000); |
161 | 204 | document.getElementById('result').value = `<t:${unix}:f>`; |
162 | | - showToast("Timestamp généré !"); |
163 | 205 | } |
164 | 206 |
|
165 | | -function showToast(message){ |
166 | | - const container = document.getElementById('toast-container'); |
167 | | - const toast = document.createElement('div'); |
168 | | - toast.className='toast show'; |
169 | | - toast.textContent = message; |
170 | | - const progress=document.createElement('div'); progress.className='progress'; toast.appendChild(progress); |
171 | | - container.appendChild(toast); |
172 | | - setTimeout(()=>{toast.classList.remove('show'); setTimeout(()=>toast.remove(),300);},5000); |
173 | | -} |
174 | 207 | </script> |
175 | 208 |
|
176 | 209 | </body> |
|
0 commit comments