diff --git a/DESIGN_SYSTEM.md b/DESIGN_SYSTEM.md
index f6ee504..8278c30 100644
--- a/DESIGN_SYSTEM.md
+++ b/DESIGN_SYSTEM.md
@@ -171,6 +171,8 @@ Regles UI :
- types visibles : `Duree`, `Heure precise`, `Pattern horaire`, `Intervalle` ;
- les libelles au-dessus des champs `hh:mm:ss` restent accessibles en `sr-only`, mais ne sont pas visibles ;
- les boutons de controle utilisent les icones `play-circle`, `pause-circle`, `record-circle`, `stop-circle`, `refresh`, `sort-time`, `scrollable`.
+- pour `Heure precise` et `Intervalle`, le refresh inline est un toggle compact de repetition automatique ; il est bloque si la frequence est inferieure a 5 minutes.
+- le formulaire `Intervalle` affiche deux champs `hh:mm:ss` compacts : duree de repetition et depart optionnel ; un depart vide signifie `Maintenant`.
Alertes timer :
diff --git a/docs/STORAGE_SCHEMA.md b/docs/STORAGE_SCHEMA.md
index 8055eae..b03f5f0 100644
--- a/docs/STORAGE_SCHEMA.md
+++ b/docs/STORAGE_SCHEMA.md
@@ -258,6 +258,7 @@ Structure initiale :
"label": "Boss",
"type": "daily_time",
"alertMode": "visible",
+ "autoRefresh": true,
"time": "12:03:00",
"targetAt": 1760000000000
},
@@ -271,8 +272,12 @@ Structure initiale :
"id": "timer4",
"label": "Event",
"type": "interval",
+ "autoRefresh": true,
"intervalMs": 1800000,
- "anchorAt": 1760000000000
+ "startMode": "time",
+ "startTime": "06:00:00",
+ "anchorAt": 1760000000000,
+ "targetAt": 1760001800000
}
]
}
@@ -281,9 +286,9 @@ Structure initiale :
Types de compte à rebours :
- `duration` : durée ponctuelle, avec `durationMs` et `targetAt`.
-- `daily_time` : occurrence ponctuelle à une heure précise, avec `time` au format `HH:MM:SS` et `targetAt`.
+- `daily_time` : occurrence à une heure précise, avec `time` au format `HH:MM:SS`, `targetAt` et `autoRefresh` optionnel.
- `time_pattern` : prochaine occurrence automatique correspondant à un pattern `HH:MM:SS`, où chaque segment peut valoir `X`.
-- `interval` : prochaine occurrence automatique toutes les X millisecondes, avec `intervalMs` et `anchorAt`.
+- `interval` : intervalle basé sur `intervalMs`, `anchorAt`, `targetAt`, `startMode`, `startTime` et `autoRefresh` optionnel. `startMode` vaut `now` ou `time`; `startTime` est présent uniquement avec `time`. `autoRefresh` n'est conservé que si l'intervalle dure au moins 5 minutes ; les anciens intervalles sans `targetAt` restent interprétés comme répétables.
Pour `time_pattern`, un segment `X` situé après un segment plus large fixé cible le premier instant de l'occurrence. Exemple : `X:24:X` cible `hh:24:00` et se répète toutes les heures.
@@ -298,6 +303,8 @@ Stockage compact :
- `laps` est omis tant qu'aucune étape n'est enregistrée.
- `countdowns` est omis tant qu'aucun compte à rebours n'est configuré.
- `countdowns[].alertMode` vaut `off`, `visible` ou `site`, et est omis si `off`.
+- `countdowns[].autoRefresh` est omis si `false`.
+- `countdowns[].startMode` et `countdowns[].startTime` sont omis pour les intervalles qui démarrent à la création.
- L'activation d'une alerte est bloquée dans l'interface si la fréquence configurée est inférieure à 5 minutes pour les comptes à rebours récurrents (`time_pattern` et `interval`). Le blocage ne dépend pas du temps restant avant la prochaine échéance.
## Outil Task Planner
diff --git a/tests/helpers/data-validation.mjs b/tests/helpers/data-validation.mjs
index f24060d..4eea9fe 100644
--- a/tests/helpers/data-validation.mjs
+++ b/tests/helpers/data-validation.mjs
@@ -261,6 +261,9 @@ export function validateSiteContent(site) {
"toolboxes.modules.timer.dailyTimeLabel",
"toolboxes.modules.timer.timePatternLabel",
"toolboxes.modules.timer.intervalLabel",
+ "toolboxes.modules.timer.intervalStartNowOption",
+ "toolboxes.modules.timer.intervalStartTimeOption",
+ "toolboxes.modules.timer.intervalStartTimeLabel",
"toolboxes.modules.timer.addCountdownButton",
"toolboxes.modules.timer.defaultCountdownLabel",
"toolboxes.modules.timer.finishedLabel",
@@ -270,6 +273,7 @@ export function validateSiteContent(site) {
"toolboxes.modules.timer.countdownsTitle",
"toolboxes.modules.timer.scrollableTitle",
"toolboxes.modules.timer.sortTitle",
+ "toolboxes.modules.timer.autoRefreshTitle",
"toolboxes.modules.timer.alertModeTitle",
"toolboxes.modules.timer.alertOffTitle",
"toolboxes.modules.timer.alertVisibleTitle",
diff --git a/website/public/data/library.json b/website/public/data/library.json
index 5a98ec6..8a6a573 100644
--- a/website/public/data/library.json
+++ b/website/public/data/library.json
@@ -1295,6 +1295,7 @@
"id": "z4",
"label": "Boss Mondial",
"type": "daily_time",
+ "autoRefresh": true,
"time": "14:00:00",
"targetAt": 1785758400000
},
diff --git a/website/public/data/site.json b/website/public/data/site.json
index 5c8cb4a..363bca8 100644
--- a/website/public/data/site.json
+++ b/website/public/data/site.json
@@ -426,15 +426,19 @@
"dailyTimeLabel": "Heure",
"timePatternLabel": "Heure / minute / seconde",
"intervalLabel": "Toutes les",
+ "intervalStartNowOption": "Maintenant",
+ "intervalStartTimeOption": "Heure précise",
+ "intervalStartTimeLabel": "Départ",
"addCountdownButton": "Ajouter",
"defaultCountdownLabel": "Timer",
"finishedLabel": "Terminé",
- "targetLabel": "Prochaine occurrence",
+ "targetLabel": "Suivant",
"stepLabel": "Étape",
"stepsTitle": "Étapes",
"countdownsTitle": "Temps restants",
"scrollableTitle": "Liste scrollable",
"sortTitle": "Trier par temps restant",
+ "autoRefreshTitle": "Répéter automatiquement",
"alertModeTitle": "Mode d'alerte",
"alertOffTitle": "Pas d'alerte",
"alertVisibleTitle": "Alerte quand la toolbox est affichée",
diff --git a/website/src/features/toolboxes/modules/TimerModule.jsx b/website/src/features/toolboxes/modules/TimerModule.jsx
index d3cf3fd..dd55fbd 100644
--- a/website/src/features/toolboxes/modules/TimerModule.jsx
+++ b/website/src/features/toolboxes/modules/TimerModule.jsx
@@ -12,6 +12,7 @@ import {
getCentiseconds,
getCountdownTargetMs,
getDailyTargetMs,
+ getIntervalAnchorMs,
getNowMs,
getTimePatternTargetMs,
getTimePatternRecurrenceMs,
@@ -32,7 +33,8 @@ const DEFAULT_COUNTDOWN_FORM = {
duration: EMPTY_TIME_PARTS,
time: EMPTY_TIME_PARTS,
pattern: EMPTY_TIME_PARTS,
- interval: EMPTY_TIME_PARTS
+ interval: EMPTY_TIME_PARTS,
+ intervalStartTime: EMPTY_TIME_PARTS
};
const ALERT_MODES = [
{ mode: "off", icon: "sound-mute" },
@@ -41,6 +43,7 @@ const ALERT_MODES = [
];
const ALERT_MIN_DELAY_MS = 5 * 60 * 1000;
const AUTO_REFRESH_COUNTDOWN_TYPES = new Set(["time_pattern", "interval"]);
+const TOGGLE_REFRESH_COUNTDOWN_TYPES = new Set(["daily_time", "interval"]);
function isAlertGuarded(countdown) {
if (countdown?.type === "interval") return Number(countdown.intervalMs) < ALERT_MIN_DELAY_MS;
@@ -52,6 +55,10 @@ function getAlertGuardMessage(textContent) {
return textContent.alertTooSoonTitle || "Alerte indisponible pour une répétition inférieure à 5 minutes";
}
+function canToggleAutoRefresh(countdown) {
+ return TOGGLE_REFRESH_COUNTDOWN_TYPES.has(countdown?.type) && !isAlertGuarded(countdown);
+}
+
function TimerValue({ ms, compact = false, showCentiseconds = true }) {
if (!showCentiseconds) return {formatDuration(ms)};
if (!compact) return {formatDurationWithCentiseconds(ms)};
@@ -64,12 +71,17 @@ function TimerValue({ ms, compact = false, showCentiseconds = true }) {
);
}
-function getCountdownMeta(countdown, textContent) {
- if (countdown.type === "duration") return `${textContent.durationType || "Durée"} · ${formatDuration(countdown.durationMs || 0)}`;
- if (countdown.type === "daily_time") return `${textContent.dailyTimeType || "Heure précise"} · ${countdown.time}`;
- if (countdown.type === "time_pattern") return `${textContent.timePatternType || "Heure / minute / seconde"} · ${countdown.pattern}`;
- if (countdown.type === "interval") return `${textContent.intervalType || "Intervalle"} · ${formatDuration(countdown.intervalMs || 0)}`;
- return "";
+function getCountdownMetaParts(countdown, textContent) {
+ if (countdown.type === "duration") return [`${textContent.durationType || "Durée"} ${formatDuration(countdown.durationMs || 0)}`];
+ if (countdown.type === "daily_time") return [`${textContent.dailyTimeType || "Heure précise"} ${countdown.time}`];
+ if (countdown.type === "time_pattern") return [`${textContent.timePatternType || "Heure / minute / seconde"} ${countdown.pattern}`];
+ if (countdown.type === "interval") {
+ const startLabel = countdown.startMode === "time" && countdown.startTime
+ ? `${textContent.intervalStartTimeLabel || "Départ"} ${countdown.startTime}`
+ : textContent.intervalStartNowOption || "Maintenant";
+ return [`${textContent.intervalType || "Intervalle"} ${formatDuration(countdown.intervalMs || 0)}`, startLabel];
+ }
+ return [];
}
function handleEditableKeyDown(event, callback) {
@@ -78,6 +90,10 @@ function handleEditableKeyDown(event, callback) {
callback();
}
+function hasTimePartValue(parts) {
+ return Boolean(String(parts?.hours || "").trim() || String(parts?.minutes || "").trim() || String(parts?.seconds || "").trim());
+}
+
export function TimerModule({ toolboxId, moduleId, context }) {
const data = context.normalizeTimerData(context.getModuleData(toolboxId, moduleId, { activeTab: "stopwatch" }));
const textContent = context.moduleText?.timer || {};
@@ -197,7 +213,23 @@ export function TimerModule({ toolboxId, moduleId, context }) {
}
if (type === "interval") {
const intervalMs = timePartsToDurationMs(draft.interval);
- if (intervalMs > 0) countdown = { id: context.uid("timer"), label, type, intervalMs, anchorAt: now };
+ const startTime = hasTimePartValue(draft.intervalStartTime) ? timePartsToString(draft.intervalStartTime) : "";
+ const startMode = startTime ? "time" : "now";
+ const anchorAt = getIntervalAnchorMs(startMode, startTime, now);
+ const targetAt = getCountdownTargetMs({ type, intervalMs, anchorAt, autoRefresh: true }, now);
+ if (intervalMs > 0) {
+ countdown = {
+ id: context.uid("timer"),
+ label,
+ type,
+ intervalMs,
+ anchorAt,
+ targetAt,
+ startMode,
+ ...(startTime ? { startTime } : {}),
+ autoRefresh: intervalMs >= ALERT_MIN_DELAY_MS
+ };
+ }
}
if (!countdown) return;
@@ -216,11 +248,39 @@ export function TimerModule({ toolboxId, moduleId, context }) {
let nextCountdown = null;
if (countdown.type === "duration") nextCountdown = { ...countdown, targetAt: now + countdown.durationMs };
if (countdown.type === "daily_time") nextCountdown = { ...countdown, targetAt: getDailyTargetMs(countdown.time, now) };
- if (countdown.type === "interval") nextCountdown = { ...countdown, anchorAt: now };
+ if (countdown.type === "interval") {
+ const anchorAt = getIntervalAnchorMs(countdown.startMode, countdown.startTime, now);
+ const targetAt = getCountdownTargetMs({ ...countdown, anchorAt, autoRefresh: true }, now);
+ nextCountdown = { ...countdown, anchorAt, targetAt };
+ }
if (!nextCountdown) return;
save({ ...data, countdowns: data.countdowns.map((item) => item.id === countdown.id ? nextCountdown : item) });
}
+ function toggleCountdownAutoRefresh(countdownId) {
+ const countdown = data.countdowns.find((item) => item.id === countdownId);
+ if (!TOGGLE_REFRESH_COUNTDOWN_TYPES.has(countdown?.type)) return;
+ if (!countdown.autoRefresh && !canToggleAutoRefresh(countdown)) {
+ context.notify?.(getAlertGuardMessage(textContent));
+ return;
+ }
+ const now = getNowMs();
+ save({
+ ...data,
+ countdowns: data.countdowns.map((item) => {
+ if (item.id !== countdownId) return item;
+ const autoRefresh = !item.autoRefresh;
+ if (item.type === "daily_time") return { ...item, autoRefresh, targetAt: getDailyTargetMs(item.time, now) };
+ if (item.type === "interval") {
+ const anchorAt = getIntervalAnchorMs(item.startMode, item.startTime, now);
+ const targetAt = getCountdownTargetMs({ ...item, anchorAt, autoRefresh: true }, now);
+ return { ...item, autoRefresh, anchorAt, targetAt };
+ }
+ return item;
+ })
+ });
+ }
+
function renameCountdown(countdownId, label) {
save({
...data,
@@ -314,7 +374,7 @@ export function TimerModule({ toolboxId, moduleId, context }) {
{activeTab === "stopwatch" ? (
{textContent.emptyCountdowns || "Aucun compte à rebours configuré."}
; return ( @@ -493,9 +562,12 @@ function CountdownList({ countdowns, nowMs, textContent, reorder, reorderEnabled {countdowns.map((countdown) => { const remainingMs = countdown.targetMs - nowMs; const expired = remainingMs <= 0; - const canReset = countdown.type === "duration" - || countdown.type === "interval" - || (countdown.type === "daily_time" && expired); + const canReset = countdown.type === "duration"; + const canToggleRefresh = TOGGLE_REFRESH_COUNTDOWN_TYPES.has(countdown.type); + const refreshBlocked = canToggleRefresh && !canToggleAutoRefresh(countdown); + const refreshTitle = refreshBlocked + ? getAlertGuardMessage(textContent) + : textContent.autoRefreshTitle || "Répéter automatiquement"; const className = [ "timer-list-item", expired ? "is-expired" : "", @@ -508,7 +580,7 @@ function CountdownList({ countdowns, nowMs, textContent, reorder, reorderEnabled return (- {getCountdownMeta(countdown, textContent)} - {expired ? textContent.finishedLabel || "Terminé" : `${textContent.targetLabel || "Prochaine occurrence"} · ${formatTargetTime(countdown.targetMs)}`} + + {getCountdownMetaParts(countdown, textContent).map((part, index) => ( + {part} + ))} + + + {expired ? textContent.finishedLabel || "Terminé" : `${textContent.targetLabel || "Prochaine occurrence"} ${formatTargetTime(countdown.targetMs)}`} +
); diff --git a/website/src/features/toolboxes/modules/timerUtils.js b/website/src/features/toolboxes/modules/timerUtils.js index 892c28c..c9ebded 100644 --- a/website/src/features/toolboxes/modules/timerUtils.js +++ b/website/src/features/toolboxes/modules/timerUtils.js @@ -113,10 +113,22 @@ export function getIntervalTargetMs(intervalMs, anchorAt, nowMs) { return safeAnchor + Math.ceil((nowMs - safeAnchor + 1) / safeIntervalMs) * safeIntervalMs; } +export function getIntervalAnchorMs(startMode, startTime, nowMs) { + if (startMode !== "time") return nowMs; + const parsed = parseTimeString(startTime); + if (!parsed) return nowMs; + const anchor = new Date(nowMs); + anchor.setHours(Number(parsed.hours), Number(parsed.minutes), Number(parsed.seconds), 0); + return anchor.getTime(); +} + export function getCountdownTargetMs(countdown, nowMs) { if (countdown.type === "duration") return Number(countdown.targetAt) || 0; - if (countdown.type === "daily_time") return Number(countdown.targetAt) || 0; + if (countdown.type === "daily_time") return countdown.autoRefresh ? getDailyTargetMs(countdown.time, nowMs) : Number(countdown.targetAt) || 0; if (countdown.type === "time_pattern") return getTimePatternTargetMs(countdown.pattern, nowMs); - if (countdown.type === "interval") return getIntervalTargetMs(countdown.intervalMs, countdown.anchorAt, nowMs); + if (countdown.type === "interval") { + if (countdown.autoRefresh) return getIntervalTargetMs(countdown.intervalMs, countdown.anchorAt, nowMs); + return Number(countdown.targetAt) || 0; + } return 0; } diff --git a/website/src/features/toolboxes/storage/toolboxStorage.js b/website/src/features/toolboxes/storage/toolboxStorage.js index cc4ec0a..a96a400 100644 --- a/website/src/features/toolboxes/storage/toolboxStorage.js +++ b/website/src/features/toolboxes/storage/toolboxStorage.js @@ -16,6 +16,8 @@ const NOTEPAD_RGB_COLOR_MAP = { const TIMER_TABS = new Set(["stopwatch", "countdown"]); const COUNTDOWN_TYPES = new Set(["duration", "daily_time", "time_pattern", "interval"]); const TIMER_ALERT_MODES = new Set(["off", "visible", "site"]); +const TIMER_INTERVAL_START_MODES = new Set(["now", "time"]); +const TIMER_MIN_AUTO_REFRESH_MS = 5 * 60 * 1000; const TASK_TYPES = new Set(["unique", "daily", "weekly"]); const COMBO_DEVICES = new Set(["playstation", "xbox", "switch", "n64", "keyboardMouse"]); const COMBO_INPUT_KINDS = new Set(["button", "direction", "key", "mouse"]); @@ -553,7 +555,7 @@ export function normalizeTimerData(data) { if (type === "daily_time") { const time = String(countdown?.time || "").trim(); const targetAt = Math.max(0, Number(countdown?.targetAt) || 0); - return isTimeString(time) && targetAt > 0 ? { ...normalized, time, targetAt } : null; + return isTimeString(time) && targetAt > 0 ? { ...normalized, time, targetAt, autoRefresh: countdown?.autoRefresh === true } : null; } if (type === "time_pattern") { const pattern = String(countdown?.pattern || "").trim().toUpperCase(); @@ -562,7 +564,21 @@ export function normalizeTimerData(data) { if (type === "interval") { const intervalMs = Math.max(0, Number(countdown?.intervalMs) || 0); const anchorAt = Math.max(0, Number(countdown?.anchorAt) || 0); - return intervalMs > 0 ? { ...normalized, intervalMs, anchorAt } : null; + const targetAt = Math.max(0, Number(countdown?.targetAt) || 0); + const startMode = TIMER_INTERVAL_START_MODES.has(countdown?.startMode) ? countdown.startMode : "now"; + const startTime = String(countdown?.startTime || "").trim(); + const autoRefresh = countdown?.autoRefresh === true || (countdown?.autoRefresh !== false && !targetAt && intervalMs >= TIMER_MIN_AUTO_REFRESH_MS); + return intervalMs > 0 + ? { + ...normalized, + intervalMs, + anchorAt, + targetAt: targetAt || anchorAt + intervalMs, + startMode: startMode === "time" && isTimeString(startTime) ? "time" : "now", + ...(startMode === "time" && isTimeString(startTime) ? { startTime } : {}), + autoRefresh: autoRefresh && intervalMs >= TIMER_MIN_AUTO_REFRESH_MS + } + : null; } return null; }) @@ -822,11 +838,14 @@ export function compactModuleDataForStorage(type, value) { } if (normalized.countdowns.length) { compact.countdowns = normalized.countdowns.map((countdown) => { - if (countdown.alertMode === "off") { - const { alertMode, ...compactCountdown } = countdown; - return compactCountdown; + const { alertMode, autoRefresh, startMode, startTime, ...compactCountdown } = countdown; + if (alertMode !== "off") compactCountdown.alertMode = alertMode; + if (autoRefresh) compactCountdown.autoRefresh = true; + if (startMode === "time" && startTime) { + compactCountdown.startMode = startMode; + compactCountdown.startTime = startTime; } - return countdown; + return compactCountdown; }); } return Object.keys(compact).length ? compact : null; diff --git a/website/src/styles/_toolboxes.scss b/website/src/styles/_toolboxes.scss index 09e0f4f..fecdb8e 100644 --- a/website/src/styles/_toolboxes.scss +++ b/website/src/styles/_toolboxes.scss @@ -3453,6 +3453,11 @@ button.combo-input-token.combo-value-grab .ui-icon { gap: 7px; } +.timer-field-spacer { + display: block; + min-height: 17px; +} + .timer-countdown-form input, .timer-countdown-form select, .timer-control-panel input { @@ -3578,6 +3583,32 @@ button.combo-input-token.combo-value-grab .ui-icon { text-align: center; } +.timer-interval-fields { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--space-2); + min-width: 0; +} + +.timer-interval-fields label { + min-width: 0; + gap: 5px; +} + +.timer-interval-fields .time-parts-input { + grid-template-columns: minmax(22px, 1fr) 4px minmax(22px, 1fr) 4px minmax(22px, 1fr); + min-height: 38px; +} + +.timer-interval-fields .time-parts-input input { + min-height: 36px; + font-size: var(--font-size-xs); +} + +.timer-interval-fields .time-parts-input span { + font-size: var(--font-size-xs); +} + .timer-control-panel > span, .timer-control-panel label span { color: var(--color-text-secondary); @@ -3658,12 +3689,13 @@ button.combo-input-token.combo-value-grab .ui-icon { .timer-entry-meta { display: flex; grid-column: 1 / -2; - flex-wrap: wrap; + flex-wrap: nowrap; min-width: 0; gap: 4px 8px; margin: 0; padding: 1px 10px 0; opacity: 0.68; + overflow: hidden; } .timer-entry-summary .timer-value, @@ -3735,7 +3767,49 @@ button.combo-input-token.combo-value-grab .ui-icon { color: var(--color-text-muted); } -.timer-inline-reset .ui-icon { +.timer-inline-refresh-toggle { + display: inline-grid; + grid-template-columns: 13px 18px; + width: 42px; + min-width: 42px; + min-height: 26px; + align-items: center; + gap: 3px; + padding: 0 4px; + border-color: rgba(165, 180, 252, 0.08); + border-radius: var(--radius-sm); + background: rgba(5, 7, 17, 0.26); + color: var(--color-text-muted); +} + +.timer-inline-refresh-toggle i { + position: relative; + display: block; + width: 18px; + height: 12px; + border: 1px solid rgba(165, 180, 252, 0.18); + border-radius: var(--radius-pill); + background: rgba(7, 10, 24, 0.72); +} + +.timer-inline-refresh-toggle i::before { + content: ""; + position: absolute; + top: 50%; + left: 2px; + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--color-text-muted); + transform: translateY(-50%); + transition: + left var(--duration-fast) var(--ease-standard), + background-color var(--duration-fast) var(--ease-standard), + box-shadow var(--duration-fast) var(--ease-standard); +} + +.timer-inline-reset .ui-icon, +.timer-inline-refresh-toggle .ui-icon { width: 14px; height: 14px; } @@ -3766,16 +3840,47 @@ button.combo-input-token.combo-value-grab .ui-icon { } .timer-entry-meta span { + display: inline-flex; + align-items: center; + gap: 7px; + min-width: 0; + overflow: hidden; color: var(--color-text-muted); font-size: var(--font-size-xs); font-weight: 700; + text-overflow: ellipsis; + white-space: nowrap; } .timer-list-item em { + display: inline-flex; + align-items: center; + gap: 7px; + flex: 0 0 auto; color: var(--color-text-muted); font-size: var(--font-size-xs); font-style: normal; font-weight: 700; + white-space: nowrap; +} + +.timer-entry-meta b { + min-width: 0; + overflow: hidden; + font: inherit; + text-overflow: ellipsis; + white-space: nowrap; +} + +.timer-entry-meta b + b::before, +.timer-entry-meta em::before { + content: ""; + display: inline-block; + width: 1px; + height: 10px; + margin-right: 7px; + background: rgba(165, 180, 252, 0.22); + vertical-align: -1px; } .timer-results-card { @@ -4185,14 +4290,16 @@ button.combo-input-token.combo-value-grab .ui-icon { } .timer-alert-mode-button:hover, -.timer-alert-mode-button.active { +.timer-alert-mode-button.active, +.timer-inline-refresh-toggle:hover:not(:disabled) { border-color: rgba(196, 181, 253, 0.2); background: rgba(21, 26, 48, 0.42); color: var(--color-text-primary); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04); } -.timer-alert-mode-button.active { +.timer-alert-mode-button.active, +.timer-inline-refresh-toggle.active { border-color: rgba(246, 196, 83, 0.26); background: linear-gradient(135deg, rgba(246, 196, 83, 0.08), rgba(139, 92, 246, 0.08)), @@ -4200,9 +4307,23 @@ button.combo-input-token.combo-value-grab .ui-icon { color: var(--color-accent-gold); } +.timer-inline-refresh-toggle.active i { + border-color: rgba(246, 196, 83, 0.36); + background: rgba(246, 196, 83, 0.12); +} + +.timer-inline-refresh-toggle.active i::before { + left: 7px; + background: var(--color-accent-gold); + box-shadow: 0 0 10px rgba(246, 196, 83, 0.28); +} + .timer-alert-mode-button:disabled, .timer-alert-mode-button:disabled:hover, -.timer-alert-mode-button.active:disabled { +.timer-alert-mode-button.active:disabled, +.timer-inline-refresh-toggle:disabled, +.timer-inline-refresh-toggle:disabled:hover, +.timer-inline-refresh-toggle.active:disabled { cursor: not-allowed; border-color: rgba(165, 180, 252, 0.025); background: rgba(5, 7, 17, 0.08); @@ -4211,7 +4332,8 @@ button.combo-input-token.combo-value-grab .ui-icon { box-shadow: none; } -.timer-alert-mode-button:disabled .ui-icon { +.timer-alert-mode-button:disabled .ui-icon, +.timer-inline-refresh-toggle:disabled .ui-icon { opacity: 0.34; }