+25
-141
templates/status.html
+25
-141
templates/status.html
···
200
</div>
201
<button type="button" class="emoji-picker-close" id="emoji-picker-close" aria-label="close emoji picker">โ</button>
202
</div>
203
-
<div class="emoji-picker-preview">
204
-
<div class="emoji-preview-block">
205
-
<span class="emoji-preview-label">current</span>
206
-
<div class="emoji-preview-emoji" id="emoji-preview-current">
207
-
{% if let Some(current) = current_status.as_ref() %}
208
-
{% if current.status.starts_with("custom:") %}
209
-
{% let emoji_name = current.status.strip_prefix("custom:").unwrap() %}
210
-
<img src="/emojis/{{emoji_name}}.png" alt="{{emoji_name}}" title="{{emoji_name}}"
211
-
onerror="this.onerror=null; this.src='/emojis/{{emoji_name}}.gif';">
212
-
{% else %}
213
-
<span title="{{ current.status }}">{{ current.status }}</span>
214
-
{% endif %}
215
-
{% else %}
216
-
<span title="happy">๐</span>
217
-
{% endif %}
218
-
</div>
219
-
</div>
220
-
<div class="emoji-preview-block">
221
-
<span class="emoji-preview-label">next</span>
222
-
<div class="emoji-preview-emoji" id="emoji-preview-next">
223
-
{% if let Some(current) = current_status.as_ref() %}
224
-
{% if current.status.starts_with("custom:") %}
225
-
{% let emoji_name = current.status.strip_prefix("custom:").unwrap() %}
226
-
<img src="/emojis/{{emoji_name}}.png" alt="{{emoji_name}}" title="{{emoji_name}}"
227
-
onerror="this.onerror=null; this.src='/emojis/{{emoji_name}}.gif';">
228
-
{% else %}
229
-
<span title="{{ current.status }}">{{ current.status }}</span>
230
-
{% endif %}
231
-
{% else %}
232
-
<span title="happy">๐</span>
233
-
{% endif %}
234
-
</div>
235
-
</div>
236
-
</div>
237
<div class="emoji-search-container">
238
<input type="text"
239
id="emoji-search"
···
1115
}
1116
1117
.emoji-picker {
1118
-
width: min(720px, 100%);
1119
-
max-height: min(90vh, 720px);
1120
background: var(--bg-secondary);
1121
border: 1px solid var(--border-color);
1122
border-radius: clamp(var(--radius), 2vw, 24px);
1123
box-shadow: 0 32px 80px rgba(0, 0, 0, 0.45);
1124
display: flex;
1125
flex-direction: column;
1126
-
gap: 1rem;
1127
-
padding: clamp(1.25rem, 5vw, 2rem);
1128
overflow: hidden;
1129
}
1130
1131
.emoji-picker-header {
1132
display: flex;
···
1169
outline: none;
1170
}
1171
1172
-
.emoji-picker-preview {
1173
-
display: flex;
1174
-
gap: 1rem;
1175
-
background: var(--bg-primary);
1176
-
border-radius: var(--radius);
1177
-
border: 1px solid var(--border-color);
1178
-
padding: 1rem;
1179
-
}
1180
-
1181
-
.emoji-preview-block {
1182
-
flex: 1;
1183
-
display: flex;
1184
-
flex-direction: column;
1185
-
align-items: center;
1186
-
gap: 0.5rem;
1187
-
}
1188
-
1189
-
.emoji-preview-label {
1190
-
font-size: 0.75rem;
1191
-
text-transform: uppercase;
1192
-
letter-spacing: 0.08em;
1193
-
color: var(--text-tertiary);
1194
-
}
1195
-
1196
-
.emoji-preview-emoji {
1197
-
width: clamp(3.25rem, 16vw, 4.5rem);
1198
-
height: clamp(3.25rem, 16vw, 4.5rem);
1199
-
display: flex;
1200
-
align-items: center;
1201
-
justify-content: center;
1202
-
font-size: clamp(2rem, 10vw, 3rem);
1203
-
border-radius: var(--radius);
1204
-
background: var(--bg-secondary);
1205
-
border: 1px solid rgba(255, 255, 255, 0.05);
1206
-
overflow: hidden;
1207
-
}
1208
-
1209
-
.emoji-preview-emoji img {
1210
-
width: 100%;
1211
-
height: 100%;
1212
-
object-fit: contain;
1213
-
}
1214
-
1215
-
.emoji-preview-emoji span {
1216
-
display: block;
1217
-
}
1218
-
1219
.emoji-search-container {
1220
margin: 0;
1221
}
···
1251
1252
.emoji-categories {
1253
display: flex;
1254
-
gap: 0.5rem;
1255
overflow-x: auto;
1256
padding-bottom: 0.5rem;
1257
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
···
1289
.emoji-grid {
1290
flex: 1;
1291
display: grid;
1292
-
grid-template-columns: repeat(auto-fill, minmax(56px, 1fr));
1293
-
gap: 0.5rem;
1294
padding-right: 0.25rem;
1295
overflow-y: auto;
1296
}
1297
1298
.emoji-option {
1299
-
background: var(--bg-primary);
1300
-
border: 1px solid transparent;
1301
-
font-size: 2rem;
1302
cursor: pointer;
1303
-
border-radius: 16px;
1304
-
transition: transform 0.15s ease, border-color 0.2s ease, background 0.2s ease;
1305
display: flex;
1306
align-items: center;
1307
justify-content: center;
1308
width: 100%;
1309
aspect-ratio: 1;
1310
-
position: relative;
1311
}
1312
1313
-
.emoji-option:hover,
1314
.emoji-option:focus-visible {
1315
-
background: var(--bg-tertiary);
1316
-
border-color: var(--accent);
1317
-
transform: translateY(-2px);
1318
-
outline: none;
1319
}
1320
1321
.emoji-option.custom-emoji img {
1322
-
width: 70%;
1323
-
height: 70%;
1324
object-fit: contain;
1325
}
1326
1327
-
.emoji-option.custom-emoji::after {
1328
-
content: '';
1329
-
position: absolute;
1330
-
inset: 8%;
1331
-
border-radius: 12px;
1332
-
pointer-events: none;
1333
-
}
1334
-
1335
@media (max-width: 640px) {
1336
.emoji-picker-overlay {
1337
padding: 0;
···
1343
height: 100%;
1344
max-height: none;
1345
border-radius: 0;
1346
-
padding: 1.25rem 1rem 1rem;
1347
-
gap: 0.75rem;
1348
-
}
1349
-
1350
-
.emoji-picker-preview {
1351
-
padding: 0.75rem;
1352
}
1353
1354
.emoji-grid {
1355
-
grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
1356
}
1357
}
1358
···
2142
const emojiGrid = document.getElementById('emoji-grid');
2143
const selectedEmoji = document.getElementById('selected-emoji');
2144
const statusInput = document.getElementById('status-input');
2145
-
const emojiPreviewCurrent = document.getElementById('emoji-preview-current');
2146
-
const emojiPreviewNext = document.getElementById('emoji-preview-next');
2147
let lastFocusBeforeEmojiPicker = null;
2148
2149
// Clear time picker
···
2153
const expiresSelect = document.getElementById('expires_in');
2154
2155
const isEmojiPickerOpen = () => emojiPickerOverlay && !emojiPickerOverlay.classList.contains('hidden');
2156
-
2157
-
const syncPreviewWithSelection = () => {
2158
-
if (emojiPreviewNext && selectedEmoji) {
2159
-
emojiPreviewNext.innerHTML = selectedEmoji.innerHTML;
2160
-
}
2161
-
};
2162
-
2163
-
syncPreviewWithSelection();
2164
2165
const openEmojiPicker = () => {
2166
if (!emojiPickerOverlay || !emojiPicker) return;
···
2181
if (emojiSearch) emojiSearch.focus();
2182
}, 60);
2183
}
2184
-
2185
-
if (emojiPreviewCurrent) {
2186
-
const currentDisplay = document.querySelector('.current-status .status-emoji');
2187
-
if (currentDisplay) {
2188
-
emojiPreviewCurrent.innerHTML = currentDisplay.innerHTML;
2189
-
} else if (selectedEmoji) {
2190
-
emojiPreviewCurrent.innerHTML = selectedEmoji.innerHTML;
2191
-
}
2192
-
}
2193
-
2194
-
syncPreviewWithSelection();
2195
2196
loadCustomEmojis().then(() => {
2197
loadEmojiCategory('frequent');
···
2314
}
2315
2316
statusInput.value = emoji;
2317
-
syncPreviewWithSelection();
2318
closeEmojiPicker();
2319
checkForChanges();
2320
});
···
2342
// Display the image in the selected emoji area
2343
selectedEmoji.innerHTML = `<img src="${img.src}" alt="${img.alt}" style="width: 100%; height: 100%; object-fit: contain;">`;
2344
statusInput.value = emojiValue;
2345
-
syncPreviewWithSelection();
2346
closeEmojiPicker();
2347
checkForChanges();
2348
});
···
2361
const emoji = e.target.getAttribute('data-emoji');
2362
selectedEmoji.textContent = emoji;
2363
statusInput.value = emoji;
2364
-
syncPreviewWithSelection();
2365
closeEmojiPicker();
2366
checkForChanges();
2367
});
···
2595
}
2596
2597
statusInput.value = emojiValue;
2598
-
syncPreviewWithSelection();
2599
closeEmojiPicker();
2600
checkForChanges();
2601
// Clear search when emoji is selected
···
200
</div>
201
<button type="button" class="emoji-picker-close" id="emoji-picker-close" aria-label="close emoji picker">โ</button>
202
</div>
203
<div class="emoji-search-container">
204
<input type="text"
205
id="emoji-search"
···
1081
}
1082
1083
.emoji-picker {
1084
+
width: min(960px, 94vw);
1085
+
height: min(90vh, 820px);
1086
background: var(--bg-secondary);
1087
border: 1px solid var(--border-color);
1088
border-radius: clamp(var(--radius), 2vw, 24px);
1089
box-shadow: 0 32px 80px rgba(0, 0, 0, 0.45);
1090
display: flex;
1091
flex-direction: column;
1092
+
gap: 1.25rem;
1093
+
padding: clamp(1.25rem, 5vw, 2.5rem);
1094
overflow: hidden;
1095
}
1096
+
1097
1098
.emoji-picker-header {
1099
display: flex;
···
1136
outline: none;
1137
}
1138
1139
.emoji-search-container {
1140
margin: 0;
1141
}
···
1171
1172
.emoji-categories {
1173
display: flex;
1174
+
gap: 0.75rem;
1175
overflow-x: auto;
1176
padding-bottom: 0.5rem;
1177
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
···
1209
.emoji-grid {
1210
flex: 1;
1211
display: grid;
1212
+
grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
1213
+
gap: 0.75rem;
1214
padding-right: 0.25rem;
1215
overflow-y: auto;
1216
}
1217
1218
.emoji-option {
1219
+
background: transparent;
1220
+
border: none;
1221
+
font-size: 2.4rem;
1222
cursor: pointer;
1223
+
transition: transform 0.15s ease;
1224
display: flex;
1225
align-items: center;
1226
justify-content: center;
1227
width: 100%;
1228
aspect-ratio: 1;
1229
+
}
1230
+
1231
+
.emoji-option:hover {
1232
+
transform: translateY(-3px) scale(1.05);
1233
}
1234
1235
.emoji-option:focus-visible {
1236
+
outline: 2px solid var(--accent);
1237
+
outline-offset: 6px;
1238
+
border-radius: 16px;
1239
}
1240
1241
.emoji-option.custom-emoji img {
1242
+
width: 75%;
1243
+
height: 75%;
1244
object-fit: contain;
1245
}
1246
1247
@media (max-width: 640px) {
1248
.emoji-picker-overlay {
1249
padding: 0;
···
1255
height: 100%;
1256
max-height: none;
1257
border-radius: 0;
1258
+
padding: 1.5rem 1rem;
1259
+
gap: 1rem;
1260
}
1261
1262
.emoji-grid {
1263
+
grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
1264
+
gap: 0.5rem;
1265
}
1266
}
1267
···
2051
const emojiGrid = document.getElementById('emoji-grid');
2052
const selectedEmoji = document.getElementById('selected-emoji');
2053
const statusInput = document.getElementById('status-input');
2054
let lastFocusBeforeEmojiPicker = null;
2055
2056
// Clear time picker
···
2060
const expiresSelect = document.getElementById('expires_in');
2061
2062
const isEmojiPickerOpen = () => emojiPickerOverlay && !emojiPickerOverlay.classList.contains('hidden');
2063
2064
const openEmojiPicker = () => {
2065
if (!emojiPickerOverlay || !emojiPicker) return;
···
2080
if (emojiSearch) emojiSearch.focus();
2081
}, 60);
2082
}
2083
2084
loadCustomEmojis().then(() => {
2085
loadEmojiCategory('frequent');
···
2202
}
2203
2204
statusInput.value = emoji;
2205
closeEmojiPicker();
2206
checkForChanges();
2207
});
···
2229
// Display the image in the selected emoji area
2230
selectedEmoji.innerHTML = `<img src="${img.src}" alt="${img.alt}" style="width: 100%; height: 100%; object-fit: contain;">`;
2231
statusInput.value = emojiValue;
2232
closeEmojiPicker();
2233
checkForChanges();
2234
});
···
2247
const emoji = e.target.getAttribute('data-emoji');
2248
selectedEmoji.textContent = emoji;
2249
statusInput.value = emoji;
2250
closeEmojiPicker();
2251
checkForChanges();
2252
});
···
2480
}
2481
2482
statusInput.value = emojiValue;
2483
closeEmojiPicker();
2484
checkForChanges();
2485
// Clear search when emoji is selected