Squash Odysseus development history

This commit is contained in:
pewdiepie-archdaemon
2026-09-11 06:04:19 +00:00
parent e5c99a5eee
commit 6ee6502010
2050 changed files with 538359 additions and 57745 deletions
+57 -3
View File
@@ -3,7 +3,9 @@
// Pure constants + zero-state helpers for the calendar UI.
// No DOM, no fetch, no global mutable state — safe to import anywhere.
export const WEEKDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
export const WEEKDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
export const WEEKDAYS_SUN = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
export const MONTHS = ['January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'];
@@ -63,17 +65,65 @@ export function _calBgImageUrl(c) {
return _isCalBgImage(c) ? c.slice(3) : '';
}
// Escape a value for safe embedding inside a single-quoted CSS `url('...')`.
// Backslashes MUST be escaped first: otherwise a trailing/embedded `\` in the
// (CalDAV-syncable, untrusted) bg-image URL would escape the closing quote we
// add for `'` and let the value break out of the string (CodeQL
// js/incomplete-sanitization). `"` is percent-encoded for good measure.
export function _cssUrlEscape(s) {
return String(s == null ? '' : s)
.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
.replace(/"/g, '%22');
}
// Returns a value safe to drop into `style="background:..."`. Falls back to
// the calendar default for bg-image events in spots where an image would be
// too small to render usefully (small grid dots, multi-day bars).
export function _calBgCss(c, fallback) {
if (_isCalBgImage(c)) {
const u = _calBgImageUrl(c);
return u ? `center/cover no-repeat url('${u.replace(/'/g, "\\'")}')` : (fallback || 'var(--accent)');
return u ? `center/cover no-repeat url('${_cssUrlEscape(u)}')` : (fallback || 'var(--accent)');
}
return c || fallback || 'var(--accent)';
}
function _hexToRgb(c) {
if (typeof c !== 'string') return null;
const m = c.trim().match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
if (!m) return null;
const hex = m[1].length === 3
? m[1].split('').map(ch => ch + ch).join('')
: m[1];
return {
r: parseInt(hex.slice(0, 2), 16),
g: parseInt(hex.slice(2, 4), 16),
b: parseInt(hex.slice(4, 6), 16),
};
}
function _relativeLuminance({ r, g, b }) {
return [r, g, b].map(v => {
const c = v / 255;
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
}).reduce((sum, c, i) => sum + c * [0.2126, 0.7152, 0.0722][i], 0);
}
function _contrastRatio(a, b) {
const light = Math.max(a, b);
const dark = Math.min(a, b);
return (light + 0.05) / (dark + 0.05);
}
export function _calReadableTextColor(bg) {
const rgb = _hexToRgb(bg);
if (!rgb) return 'var(--fg)';
const lum = _relativeLuminance(rgb);
const white = _contrastRatio(lum, 1);
const ink = _contrastRatio(lum, 0.006);
return ink >= white ? '#111820' : '#ffffff';
}
// ── date helpers ──
// `YYYY-MM-DD` string from a Date.
@@ -82,13 +132,17 @@ export function _ds(d) {
}
export function _addDays(dateStr, n) {
if (typeof dateStr !== 'string' || !dateStr) return '';
const d = new Date(dateStr + 'T00:00:00');
if (isNaN(d)) return '';
d.setDate(d.getDate() + n);
return _ds(d);
}
export function _shiftDT(iso, days) {
if (typeof iso !== 'string' || !iso) return '';
const d = new Date(iso);
if (isNaN(d)) return '';
d.setDate(d.getDate() + days);
return _ds(d) + (iso.length > 10 ? 'T' + iso.slice(11) : '');
}
@@ -111,7 +165,7 @@ export function _tzOffset() {
// bucket by the USER's local date. Without this an event at
// "2026-05-13T22:00:00Z" (07:00 May 14 JST) would render on May 13.
export function _localDateOf(isoStr) {
if (!isoStr) return '';
if (typeof isoStr !== 'string' || !isoStr) return '';
if (isoStr.length === 10) return isoStr;
if (/[Zz]$|[+\-]\d{2}:?\d{2}$/.test(isoStr)) {
const d = new Date(isoStr);