diff --git a/src/common/assets/global.css b/src/common/assets/global.css index 3d52b3d..10102b0 100644 --- a/src/common/assets/global.css +++ b/src/common/assets/global.css @@ -26,3 +26,19 @@ scrollbar-width: thin; scrollbar-color: var(--bg-active) transparent; } + +html { + padding: 0; + margin: 0; +} + +body { + background: var(--bg); + color: var(--text); + font-family: 'Georgia', serif; + font-size: 14px; + line-height: 1.5; + width: 100dvw; + height: 100dvh; + overflow: hidden; +} \ No newline at end of file diff --git a/src/common/assets/modal.module.css b/src/common/assets/modal.module.css index 6d9ce73..f36a4fc 100644 --- a/src/common/assets/modal.module.css +++ b/src/common/assets/modal.module.css @@ -7,7 +7,7 @@ max-width: 100%; height: 100%; max-height: 100%; - display: flex; + display: none; align-items: center; justify-content: center; background: transparent; @@ -17,6 +17,11 @@ &::backdrop { background: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(8px); + } + + &[open] { + display: flex; } } @@ -59,6 +64,7 @@ border: none; border-radius: var(--radius); cursor: pointer; + padding: 0; &:hover { color: var(--text); diff --git a/src/common/assets/ui.module.css b/src/common/assets/ui.module.css index a94ba44..68517ad 100644 --- a/src/common/assets/ui.module.css +++ b/src/common/assets/ui.module.css @@ -2,7 +2,7 @@ /* ─── Form Fields ─────────────────────────────────────────── */ -.input { +.input, input, textarea { width: 100%; padding: 8px 12px; background: var(--bg); @@ -37,7 +37,7 @@ /* ─── Buttons ─────────────────────────────────────────────── */ -.button { +.button, button { padding: 8px 16px; border-radius: var(--radius); font-size: 14px; @@ -46,6 +46,7 @@ border: none; background: transparent; transition: all var(--transition); + color: var(--text); } .buttonPrimary { @@ -59,6 +60,17 @@ } } +.buttonDanger { + composes: button; + background: var(--danger, #dc2626); + color: var(--bg); + font-weight: 500; + + &:hover { + background: var(--danger-alt, #b91c1c); + } +} + .buttonSecondary { composes: button; border: 1px solid var(--border); diff --git a/src/common/components/Modal.tsx b/src/common/components/Modal.tsx index 9b0927a..25ccb41 100644 --- a/src/common/components/Modal.tsx +++ b/src/common/components/Modal.tsx @@ -23,6 +23,7 @@ export const Modal = ({ children, open, title, onClose, sidebar, footer, ['class if (open) { ref.current?.showModal(); } else { + console.log(ref.current); ref.current?.close(); } }, [open]); diff --git a/src/games/horde/assets/favicon.ico b/src/games/horde/assets/favicon.ico new file mode 100644 index 0000000..2ebbe7c Binary files /dev/null and b/src/games/horde/assets/favicon.ico differ diff --git a/src/games/horde/assets/leaderboard-modal.module.css b/src/games/horde/assets/leaderboard-modal.module.css index 47bbb09..a35c831 100644 --- a/src/games/horde/assets/leaderboard-modal.module.css +++ b/src/games/horde/assets/leaderboard-modal.module.css @@ -1,5 +1,6 @@ .modal { - width: 480px; + max-width: 480px; + height: fit-content; } .loading, diff --git a/src/games/horde/assets/manage-workers-modal.module.css b/src/games/horde/assets/manage-workers-modal.module.css index 9a7e674..4fe5a2c 100644 --- a/src/games/horde/assets/manage-workers-modal.module.css +++ b/src/games/horde/assets/manage-workers-modal.module.css @@ -1,5 +1,6 @@ .modal { - width: 480px; + max-width: 480px; + height: fit-content; } .loading { @@ -57,31 +58,10 @@ gap: 8px; } -.saveBtn { - padding: 8px 16px; - border: none; - border-radius: var(--radius); - background: var(--accent); - color: var(--bg); - transition: opacity var(--transition); - - &:hover { - opacity: 0.85; - } +.saveBtn { + composes: buttonSecondary from '@common/assets/ui.module.css'; } -.deleteBtn { - padding: 8px 16px; - border: 1px solid var(--border); - border-radius: var(--radius); - background: transparent; - color: var(--text-muted); - margin-left: auto; - transition: all var(--transition); - - &:hover { - background: var(--accent); - border-color: var(--accent); - color: var(--bg); - } +.deleteBtn { + composes: buttonDanger from '@common/assets/ui.module.css'; } \ No newline at end of file diff --git a/src/games/horde/assets/modal.module.css b/src/games/horde/assets/modal.module.css deleted file mode 100644 index 42d7c68..0000000 --- a/src/games/horde/assets/modal.module.css +++ /dev/null @@ -1,72 +0,0 @@ -.overlay { - position: fixed; - inset: 0; - background: rgba(0, 0, 0, 0.6); - display: flex; - align-items: center; - justify-content: center; - z-index: 1000; -} - -.modal { - background: var(--bg); - border: 1px solid var(--border); - border-radius: 8px; - display: flex; - flex-direction: column; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); - max-height: 80vh; -} - -.header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 14px 16px; - border-bottom: 1px solid var(--border); - flex-shrink: 0; -} - -.title { - font-size: 16px; - font-weight: bold; - color: var(--text); -} - -.closeButton { - display: flex; - align-items: center; - justify-content: center; - width: 28px; - height: 28px; - color: var(--text-muted); - background: transparent; - border: none; - border-radius: var(--radius); - cursor: pointer; - - &:hover { - color: var(--text); - background: var(--bg-hover); - } -} - -.body { - flex: 1; - overflow-y: auto; - padding: 16px; - display: flex; - flex-direction: column; - gap: 14px; - min-height: 0; -} - -.footer { - padding: 12px 16px; - border-top: 1px solid var(--border); - display: flex; - flex-direction: row; - gap: 8px; - flex-shrink: 0; - align-items: center; -} \ No newline at end of file diff --git a/src/games/horde/assets/options-modal.module.css b/src/games/horde/assets/options-modal.module.css index 4e03a4b..d3da80f 100644 --- a/src/games/horde/assets/options-modal.module.css +++ b/src/games/horde/assets/options-modal.module.css @@ -1,5 +1,6 @@ .modal { - width: 380px; + max-width: 380px; + height: fit-content; } .label { @@ -15,27 +16,9 @@ } .saveBtn { - padding: 8px 16px; - border: none; - border-radius: var(--radius); - background: var(--accent); - color: var(--bg); - transition: opacity var(--transition); - - &:hover { - opacity: 0.85; - } + composes: buttonSecondary from '@common/assets/ui.module.css'; } .clearBtn { - padding: 8px 16px; - border: 1px solid var(--border); - border-radius: var(--radius); - background: transparent; - color: var(--text); - transition: background var(--transition); - - &:hover { - background: var(--bg-hover); - } + composes: buttonSecondary from '@common/assets/ui.module.css'; } \ No newline at end of file diff --git a/src/games/horde/assets/pwa_icon.png b/src/games/horde/assets/pwa_icon.png new file mode 100644 index 0000000..76aacb0 Binary files /dev/null and b/src/games/horde/assets/pwa_icon.png differ diff --git a/src/games/horde/assets/style.css b/src/games/horde/assets/style.css deleted file mode 100644 index c0e598b..0000000 --- a/src/games/horde/assets/style.css +++ /dev/null @@ -1,50 +0,0 @@ -@import "@common/assets/global.css"; - -body { - background: var(--bg); - color: var(--text); - font-family: 'Georgia', serif; - font-size: 14px; - line-height: 1.5; - width: 100dvw; - height: 100dvh; - overflow: hidden; -} - -button { - cursor: pointer; - background: none; - border: none; - color: var(--text-muted); - font-family: inherit; - font-size: inherit; - transition: color var(--transition), background var(--transition); - border-radius: var(--radius); - display: inline-flex; - flex-direction: row; - align-items: center; - gap: 4px; - padding: 4px 8px; - - &:hover { - color: var(--text); - background: var(--bg-hover); - } -} - -input, -textarea { - background: var(--bg-active); - border: 1px solid var(--border); - border-radius: var(--radius); - color: var(--text); - font-family: inherit; - font-size: inherit; - padding: 6px 10px; - outline: none; - transition: border-color var(--transition); - - &:focus { - border-color: var(--accent); - } -} \ No newline at end of file diff --git a/src/games/horde/components/modals/leaderboard-modal.tsx b/src/games/horde/components/modals/leaderboard-modal.tsx index aeac6cd..bd4def3 100644 --- a/src/games/horde/components/modals/leaderboard-modal.tsx +++ b/src/games/horde/components/modals/leaderboard-modal.tsx @@ -1,10 +1,8 @@ -import clsx from "clsx"; import { useEffect, useState } from "preact/hooks"; import { useHordeState } from "../../contexts/state"; import { fetchLeaderboard, type LeaderboardEntry } from "../../utils/api"; import { formatNumber, formatTime } from "@common/utils"; import { Modal } from "@common/components/Modal"; -import modalStyles from "../../assets/modal.module.css"; import styles from "../../assets/leaderboard-modal.module.css"; interface Props { @@ -94,55 +92,49 @@ export const LeaderboardModal = ({ open, onClose }: Props) => { return () => { cancelled = true; }; }, [open, user?.username]); + const nextRow = rows.length >= 2 ? rows[rows.length - 2] : null; + const footer = user && nextRow?.diff && nextRow.diff > 0 && kudosPerHour > 0 + ? (() => { + const secs = Math.ceil((nextRow.diff / kudosPerHour) * 3600); + return ( + + Time to #{nextRow.rank}: {formatTime(secs)} + ({formatNumber(Math.round(kudosPerHour))} kudos/h) + + ); + })() + : undefined; + return ( - -
- Leaderboard -
-
- {loading &&

Loading…

} - {error &&

{error}

} - {!loading && !error && rows.length > 0 && ( - - - - - - - {user && } + + {loading &&

Loading…

} + {error &&

{error}

} + {!loading && !error && rows.length > 0 && ( +
#UsernameKudosDiff
+ + + + + + {user && } + + + + {rows.map(r => ( + + + + + {user && ( + + )} - - - {rows.map(r => ( - - - - - {user && ( - - )} - - ))} - -
#UsernameKudosDiff
{r.rank}{r.username}{formatNumber(r.kudos)} 0 ? styles.above : styles.below) : undefined}> + {r.diff !== undefined ? `+${formatNumber(r.diff)}` : '—'} +
{r.rank}{r.username}{formatNumber(r.kudos)} 0 ? styles.above : styles.below))}> - {r.diff !== undefined ? `+${formatNumber(r.diff)}` : '—'} -
- )} -
- {(() => { - if (!user || rows.length < 2 || kudosPerHour <= 0) return null; - const nextRow = rows[rows.length - 2]; - if (!nextRow.diff || nextRow.diff <= 0) return null; - const secs = Math.ceil((nextRow.diff / kudosPerHour) * 3600); - return ( -
- - Time to #{nextRow.rank}: {formatTime(secs)} - ({formatNumber(Math.round(kudosPerHour))} kudos/h) - -
- ); - })()} + ))} + + + )}
); }; diff --git a/src/games/horde/components/modals/manage-workers-modal.tsx b/src/games/horde/components/modals/manage-workers-modal.tsx index 05cb3e3..5a2dda5 100644 --- a/src/games/horde/components/modals/manage-workers-modal.tsx +++ b/src/games/horde/components/modals/manage-workers-modal.tsx @@ -1,9 +1,7 @@ -import clsx from "clsx"; import { useEffect, useState } from "preact/hooks"; import { useHordeState } from "../../contexts/state"; import { fetchWorker, updateWorker, deleteWorker, type WorkerData } from "../../utils/api"; import { Modal } from "@common/components/Modal"; -import modalStyles from "../../assets/modal.module.css"; import styles from "../../assets/manage-workers-modal.module.css"; interface Props { @@ -80,53 +78,48 @@ export const ManageWorkersModal = ({ open, onClose }: Props) => { }; return ( - -
- Manage Workers -
-
- {loading &&

Loading…

} - {!loading && user && workerDetails.map(w => { - const edit = edits[w.id] ?? { name: w.name, info: w.info ?? '', maintenance_mode: w.maintenance_mode }; - return ( -
-
{w.name}
- -