Prompt utilisé pour régénérer cette page :
Page: Timekeeper — Configurable Countdown Timer
Category: sandbox
Description: "Time tracking and management application"
Icon: "clock-outline"
Tags: ["time-tracking", "productivity", "legacy"]
Status: ["quarantine"] (legacy code pending migration)
Front matter (index.md):
---
title: "Timekeeper"
description: "Time tracking and management application"
icon: "clock-outline"
tags: ["time-tracking", "productivity", "legacy"]
status: ["quarantine"]
---
Body content (index.md):
Single line: "Legacy time tracking project pending migration."
The actual UI is constructed by the legacy Phasme templating system via XML files.
Directory structure:
- index.md — Hugo page (minimal content)
- index.html.xml — Phasme template for timer page
- help.html.xml — Phasme template for help page
- setup.html.xml — Phasme template for configuration page (~1700 lines)
- index.js — main timer application
- setup.js — configuration page controller
- robots.txt — "User-agent: *\nDisallow:" (allow all)
- _css/default.scss/ — SCSS directory with partitioned stylesheets:
- index.scss (imports + fullscreen rules)
- _header.scss
- _main.scss
- _sidebar-left.scss
- _table.scss
=== Phasme XML templates ===
All use <page phasme:template="default"> with phasme namespace.
Common meta: author=Cylian, copyright=2013-2019, layout=ColumnRow, title=Timekeeper.
index.html.xml (timer page):
- Links: /index.js (app), /_css/default.css (style)
- Header: "Timekeper" + "Timer" + spacer + btn-reset (restore icon) + btn-control (play/pause icons, initially hidden) + spacer + btn-fullscreen
- Sidebar (left): 3 links — About timekeeper, Timer (focus), Configure
- Main (class="timekeeper"): <output id="output"></output>
help.html.xml (about page):
- Links: /_css/default.css only
- Header: "Timekeper" + "About"
- Sidebar: same 3 links (About focus)
- Main (class="help"): h1 "Timekeeper (Noun)" + 3 definitions (ol/li). h1 "Notice" + 2 paragraphs about config persistence. h1 "Controls" + table with 9 rows mapping icons/keys to actions (save, play, pause, restore, fullscreen, space, f, h, escape).
setup.html.xml (configuration page, ~1700 lines):
- Links: /setup.js (app), /_css/default.css (style)
- Header: "Timekeper" + "Configure" + btn-save (content-save-outline icon)
- Sidebar: links + sections organized by config mode level (mode-3, mode-6, mode-9):
- General: Configuration mode, Set timer, Custom messages
- Layout: Geometry, Inside margin
- Style: Page background, Timer background, Border, Radius
- Typography: Text style, Spacing, Variant, Shadow
- Main: form#form-setup with 15+ config sections, each with header + form fields.
Sections use data-storage="org.cylian.timekeeper.*" attributes for localStorage binding.
Config mode selector: Simple (3), Standard (6), Advanced (9) — controls section visibility.
Timer units: century/year/month/week/day/hour/minute/second — each with value + 3 format strings (f0/f1/fn) using {0} placeholder.
All form fields bound to localStorage keys via data-storage attributes.
=== index.js (main timer) ===
Imports (legacy CDN): panic_osd.js, fullscreen.js, panic.js, storage.js from https://static.cylian.org/_lib/
STORAGE_PIT_KEY: 'org.cylian.timekeeper.pit'
State: _cfg = {pit, handler}, _out = #output element.
String helpers:
- _strPad(nb, f): pads number string to format length.
- _strFormat(nb, f): picks format string (f[0]=zero, f[1]=singular, f[2]=plural), replaces {N} patterns with padded number.
Timer logic:
- _ticker(): computes delta = pit - Date.now(). If negative: shows completed message, fires panic notice, stops. Otherwise: builds output string by iterating timer config units (largest first), divides delta by weight, formats each unit, concatenates prefix + units + suffix. Writes to _out.innerHTML.
Lifecycle:
- _start(): if already running, return. Reads PIT from localStorage. Number type: use as-is. String starting with "+": delta mode (Date.now() + parseInt). String: parseInt. Undefined: computes from sum of (unit.value * unit.weight). Saves PIT, starts setInterval(_ticker, 250) with immediate setTimeout. Updates play/pause button visibility.
- _stop(): stores PIT as delta string "+{pit-now}", clears interval, updates buttons.
- _reset(): stops, removes PIT from storage, restarts.
Fullscreen: _fullscreen(b) via fullscreen.js library. Toggles or forces exit.
Event listeners:
- #btn-control click: toggle start/stop
- #btn-reset click: confirm dialog then reset
- #btn-fullscreen click: toggle fullscreen
- keydown: Space=toggle, Escape=exit fullscreen, h=go to /help.html, f=fullscreen
Init sequence:
1. Check config: if settings.level undefined, redirect to /setup.html
2. Build _cfg.message from localStorage (prefix, suffix, completed)
3. Build _cfg.timer array: 8 units (century→second), each with name, value, weight (ms), format[3]. Default weights: century=3155760000000, year=31556952000, month=2592000000, week=604800000, day=86400000, hour=3600000, minute=60000, second=1000.
4. Load external font if fontUrl set (creates <link> element)
5. Apply styles from localStorage:
- Background: color | image (with size/position/repeat) | gradient (type + value)
- Opacity: transparent | color
- Geometry: flexbox (display flex, justifyContent, alignItems, width/height) | coordinate (top/right/bottom/left/width/height)
- Padding: 4 sides
- Border: per-side enable (on/off) + width/style/color
- Border radius: 4 corners
- Typography: color, fontFamily, fontSize, fontWeight, fontStyle
- Spacing: lineHeight, letterSpacing
- Font variants: caps, numeric (slashed-zero, ordinal, figure, spacing, fraction), alternates, east-asian, ligatures (common, discretionary, historical, contextual)
- Text shadow: on/off + x/y/blur/color
6. Flex compatibility check
7. Start timer
=== setup.js (config page) ===
Imports (legacy CDN): panic_osd.js, conditional-display.js, panic.js, modal.js, storage.js, formular.js from https://static.cylian.org/_lib/
_form = form('#form-setup')
_load(): iterates all localStorage keys, builds data object.
_save(data): preserves PIT key, clears storage, writes all settings back.
Event: form change → updates conditional display. #btn-save click → form.submit() + alert.
Init: sets _form.onSubmit=_save, refreshes form data, initializes conditional display (unchecked first, then checked).
=== _css/default.scss/index.scss ===
Variables: $border-size: 12px
Imports: _main, _header, _sidebar-left, _table
Fullscreen rules: vendor-prefixed (webkit/moz/ms/standard) — width/height 100vw/100vh.
=== _header.scss ===
header#layout-header: flex-start, center aligned. Color: gray-400.
x-spacer: flex 1 auto. span items: flex 0 auto, padding 2*border, font 3*border, small-caps. First span: 240px basis, light bg.
Link items (a): flex centered, 36x36px, rounded, hover gray bg. Hidden children: display none.
=== _main.scss ===
main.timekeeper#layout-main: relative position, no margin/padding, background origin/clip/attachment, overflow hidden, user-select none.
main.timekeeper output: block, absolute position, text-align center, overflow hidden.
main#layout-main (settings): margin 2*border. h1: 24px bold, nth-child spacing. h2: 18px gray. section: flex row. section>header: 240px flex basis. section>div: flex 1. Form field spacing.
=== _sidebar-left.scss ===
aside#layout-sidebar-left: light bg (243,245,247), padding top. Links: border margins, .focus = orange. h6: 1.5em small-caps, gray, bottom border. hr: padding, no border.
=== _table.scss ===
table: collapsed, 100% width. tbody: vertical middle. td: 100% width, 6px padding, left align, nowrap. th: 0 width, center, nowrap.
Page entièrement générée et maintenue par IA, sans intervention humaine.