feat: save progress on web server foundation and add new tickets
This commit is contained in:
36
src/web/public/script.js
Normal file
36
src/web/public/script.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
function formatUptime(seconds) {
|
||||||
|
if (seconds < 0) return "0s";
|
||||||
|
|
||||||
|
const days = Math.floor(seconds / (3600 * 24));
|
||||||
|
const hours = Math.floor((seconds % (3600 * 24)) / 3600);
|
||||||
|
const minutes = Math.floor((seconds % 3600) / 60);
|
||||||
|
const secs = Math.floor(seconds % 60);
|
||||||
|
|
||||||
|
const parts = [];
|
||||||
|
if (days > 0) parts.push(`${days}d`);
|
||||||
|
if (hours > 0) parts.push(`${hours}h`);
|
||||||
|
if (minutes > 0) parts.push(`${minutes}m`);
|
||||||
|
parts.push(`${secs}s`);
|
||||||
|
|
||||||
|
return parts.join(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUptime() {
|
||||||
|
const el = document.getElementById("uptime-display");
|
||||||
|
if (!el) return;
|
||||||
|
|
||||||
|
const startTimestamp = parseInt(el.getAttribute("data-start-timestamp"), 10);
|
||||||
|
if (isNaN(startTimestamp)) return;
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const elapsedSeconds = (now - startTimestamp) / 1000;
|
||||||
|
|
||||||
|
el.textContent = formatUptime(elapsedSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
// Update immediately to prevent stale content flash if possible
|
||||||
|
updateUptime();
|
||||||
|
// Update every second
|
||||||
|
setInterval(updateUptime, 1000);
|
||||||
|
});
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
import { BaseLayout } from "../views/layout";
|
import { BaseLayout } from "../views/layout";
|
||||||
|
import { formatUptime } from "../utils/format";
|
||||||
|
|
||||||
export function homeRoute(): Response {
|
export function homeRoute(): Response {
|
||||||
|
const uptime = formatUptime(process.uptime());
|
||||||
|
const startTimestamp = Date.now() - (process.uptime() * 1000);
|
||||||
|
|
||||||
const content = `
|
const content = `
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h2>Welcome</h2>
|
<h2>Welcome</h2>
|
||||||
@@ -9,6 +13,7 @@ export function homeRoute(): Response {
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<h3>Status</h3>
|
<h3>Status</h3>
|
||||||
<p>System operational.</p>
|
<p>System operational.</p>
|
||||||
|
<p><strong>Uptime:</strong> <span id="uptime-display" data-start-timestamp="${Math.floor(startTimestamp)}">${uptime}</span></p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
24
src/web/utils/format.test.ts
Normal file
24
src/web/utils/format.test.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { describe, expect, it } from "bun:test";
|
||||||
|
import { formatUptime } from "./format";
|
||||||
|
|
||||||
|
describe("formatUptime", () => {
|
||||||
|
it("formats seconds correctly", () => {
|
||||||
|
expect(formatUptime(45)).toBe("45s");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("formats minutes and seconds", () => {
|
||||||
|
expect(formatUptime(65)).toBe("1m 5s");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("formats hours, minutes, and seconds", () => {
|
||||||
|
expect(formatUptime(3665)).toBe("1h 1m 5s");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("formats days correctly", () => {
|
||||||
|
expect(formatUptime(90061)).toBe("1d 1h 1m 1s");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("handles zero", () => {
|
||||||
|
expect(formatUptime(0)).toBe("0s");
|
||||||
|
});
|
||||||
|
});
|
||||||
20
src/web/utils/format.ts
Normal file
20
src/web/utils/format.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Formats a duration in seconds into a human-readable string.
|
||||||
|
* Example: 3665 -> "1h 1m 5s"
|
||||||
|
*/
|
||||||
|
export function formatUptime(seconds: number): string {
|
||||||
|
if (seconds < 0) return "0s";
|
||||||
|
|
||||||
|
const days = Math.floor(seconds / (3600 * 24));
|
||||||
|
const hours = Math.floor((seconds % (3600 * 24)) / 3600);
|
||||||
|
const minutes = Math.floor((seconds % 3600) / 60);
|
||||||
|
const secs = Math.floor(seconds % 60);
|
||||||
|
|
||||||
|
const parts = [];
|
||||||
|
if (days > 0) parts.push(`${days}d`);
|
||||||
|
if (hours > 0) parts.push(`${hours}h`);
|
||||||
|
if (minutes > 0) parts.push(`${minutes}m`);
|
||||||
|
parts.push(`${secs}s`);
|
||||||
|
|
||||||
|
return parts.join(" ");
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ export function BaseLayout({ title, content }: LayoutProps): string {
|
|||||||
<footer>
|
<footer>
|
||||||
<p>© ${new Date().getFullYear()} Aurora Bot</p>
|
<p>© ${new Date().getFullYear()} Aurora Bot</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
<script src="/script.js" defer></script>
|
||||||
</body>
|
</body>
|
||||||
</html>`;
|
</html>`;
|
||||||
}
|
}
|
||||||
|
|||||||
34
tickets/2026-01-07-responsive-mobile-layout.md
Normal file
34
tickets/2026-01-07-responsive-mobile-layout.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# 2026-01-07-responsive-mobile-layout.md: Responsive Layout & Mobile Optimization
|
||||||
|
|
||||||
|
**Status:** Draft
|
||||||
|
**Created:** 2026-01-07
|
||||||
|
**Tags:** responsive, mobile, layout, css
|
||||||
|
|
||||||
|
## 1. Context & User Story
|
||||||
|
* **As a:** User accessing the dashboard from a mobile device
|
||||||
|
* **I want to:** View and navigate the content easily without horizontal scrolling or broken layouts
|
||||||
|
* **So that:** I can monitor the bot status from my phone while on the go.
|
||||||
|
|
||||||
|
## 2. Technical Requirements
|
||||||
|
### Data Model Changes
|
||||||
|
- N/A
|
||||||
|
|
||||||
|
### API / Interface
|
||||||
|
- N/A
|
||||||
|
|
||||||
|
## 3. Constraints & Validations (CRITICAL)
|
||||||
|
- **Breakpoints:** Use standard breakpoints (mobile first approach preferred, or standard desktop-first with max-width queries).
|
||||||
|
- **Touch Targets:** Interactive elements must be at least 44x44px on mobile devices.
|
||||||
|
- **Viewport:** Ensure meta viewport tag covers all device widths (already present in layout, verify settings).
|
||||||
|
|
||||||
|
## 4. Acceptance Criteria
|
||||||
|
1. [ ] The navigation bar adapts to mobile screens (collapses into a hamburger menu or utilizes a scrollable tab bar).
|
||||||
|
2. [ ] Main content padding adjusts for smaller screens to maximize usable space.
|
||||||
|
3. [ ] Grid/Flex layouts stack vertically on mobile screens.
|
||||||
|
4. [ ] Typography sizes scale appropriately (smaller headers on mobile).
|
||||||
|
|
||||||
|
## 5. Implementation Plan
|
||||||
|
- [ ] Add media queries to `style.css` for tablet and mobile breakpoints.
|
||||||
|
- [ ] Modify the `<header>` styles to accommodate a more flexible layout.
|
||||||
|
- [ ] Implement a simple JS toggle for mobile navigation if a hamburger menu is chosen, OR style a horizontal scrollable nav.
|
||||||
|
- [ ] Adjust `.card` and container margins for mobile contexts.
|
||||||
34
tickets/2026-01-07-ux-enhancements-and-animations.md
Normal file
34
tickets/2026-01-07-ux-enhancements-and-animations.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# 2026-01-07-ux-enhancements-animations.md: UX Enhancements & Micro-Interactions
|
||||||
|
|
||||||
|
**Status:** Draft
|
||||||
|
**Created:** 2026-01-07
|
||||||
|
**Tags:** ux, animation, interactivity, frontend
|
||||||
|
|
||||||
|
## 1. Context & User Story
|
||||||
|
* **As a:** User interacting with the dashboard
|
||||||
|
* **I want to:** See smooth transitions and immediate feedback when interacting with elements
|
||||||
|
* **So that:** The application feels responsive, "alive," and high-quality.
|
||||||
|
|
||||||
|
## 2. Technical Requirements
|
||||||
|
### Data Model Changes
|
||||||
|
- N/A
|
||||||
|
|
||||||
|
### API / Interface
|
||||||
|
- N/A
|
||||||
|
|
||||||
|
## 3. Constraints & Validations (CRITICAL)
|
||||||
|
- **Performance:** Animations must use `transform` and `opacity` properties to ensure 60fps performance without triggering expensive layout reflows.
|
||||||
|
- **Accessibility:** Respect `prefers-reduced-motion` media queries to disable animations for sensitive users.
|
||||||
|
- **Subtlety:** Animations should be fast and subtle (e.g., 150ms-300ms), not distracting.
|
||||||
|
|
||||||
|
## 4. Acceptance Criteria
|
||||||
|
1. [ ] Content fades in smoothly when the page loads.
|
||||||
|
2. [ ] Interactive elements (buttons, links, cards) have hover effects (scale, lift, or glow) that provide visual feedback.
|
||||||
|
3. [ ] A subtle, dynamic background effect (e.g., slow gradient mesh or blur) is implemented to remove the "flat" look.
|
||||||
|
4. [ ] Loading states (skeletons or spinners) are available for future dynamic content.
|
||||||
|
|
||||||
|
## 5. Implementation Plan
|
||||||
|
- [ ] Add keyframe animations for entry transitions (fade-in, slide-up) in `style.css`.
|
||||||
|
- [ ] Apply hover transitions to `.card` and navigation links.
|
||||||
|
- [ ] Implement a subtle background gradient using `background-image` or pseudo-elements.
|
||||||
|
- [ ] Add `prefers-reduced-motion` overrides.
|
||||||
37
tickets/2026-01-07-visual-design-system-overhaul.md
Normal file
37
tickets/2026-01-07-visual-design-system-overhaul.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# 2026-01-07-visual-design-system-overhaul.md: Visual Design System Overhaul
|
||||||
|
|
||||||
|
**Status:** Draft
|
||||||
|
**Created:** 2026-01-07
|
||||||
|
**Tags:** ui, css, design-system, aesthetics
|
||||||
|
|
||||||
|
## 1. Context & User Story
|
||||||
|
* **As a:** User of the Aurora Web Dashboard
|
||||||
|
* **I want to:** Experience a cohesive, modern, and premium visual design
|
||||||
|
* **So that:** The application feels professional, trustworthy, and pleasant to use for extended periods.
|
||||||
|
|
||||||
|
## 2. Technical Requirements
|
||||||
|
### Data Model Changes
|
||||||
|
- N/A
|
||||||
|
|
||||||
|
### API / Interface
|
||||||
|
- N/A
|
||||||
|
|
||||||
|
## 3. Constraints & Validations (CRITICAL)
|
||||||
|
- **CSS Variables:** Must use CSS Custom Properties for all colors, spacing, and typography to ensure theming capabilities.
|
||||||
|
- **Color Palette:** Use an HSL-based color system (e.g., `--primary-h`, `--primary-s`, `--primary-l`) to allow for opacity manipulations.
|
||||||
|
- **Typography:** Integrate a modern sans-serif font like 'Inter' or 'Outfit' from Google Fonts. Do not rely on system defaults.
|
||||||
|
- **Performance:** Load fonts efficiently (display: swap).
|
||||||
|
|
||||||
|
## 4. Acceptance Criteria
|
||||||
|
1. [ ] `style.css` is refactored to use a comprehensive set of root variables (colors, spacing, radii, shadows).
|
||||||
|
2. [ ] A modern font (Inter/Outfit) is imported and applied globally.
|
||||||
|
3. [ ] Hardcoded hex values are removed in favor of CSS variables.
|
||||||
|
4. [ ] Common components (Cards, Buttons, Inputs, Tables) have distinct, premium styles defined.
|
||||||
|
5. [ ] The color palette includes primary, secondary, background, surface, and semantic colors (success, error, warning).
|
||||||
|
|
||||||
|
## 5. Implementation Plan
|
||||||
|
- [ ] Define the HSL color palette and typography in `:root`.
|
||||||
|
- [ ] Import Google Fonts in `layout.ts` or via `@import` in CSS.
|
||||||
|
- [ ] Refactor existing `.card` and body styles to use the new tokens.
|
||||||
|
- [ ] Create utility classes for common spacing/layout needs if necessary (or keep it semantic).
|
||||||
|
- [ ] Add styles for buttons and links with proper hover/active states.
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
# 2026-01-07-web-server-foundation: Web Server Infrastructure Foundation
|
|
||||||
|
|
||||||
**Status:** Done
|
|
||||||
**Created:** 2026-01-07
|
|
||||||
**Tags:** infrastructure, web, core
|
|
||||||
|
|
||||||
## 1. Context & User Story
|
|
||||||
* **As a:** Developer
|
|
||||||
* **I want to:** Establish a lightweight, integrated web server foundation within the existing codebase.
|
|
||||||
* **So that:** We can serve internal tools (Workbench) or public pages (Leaderboard) with minimal friction, avoiding complex separate build pipelines.
|
|
||||||
|
|
||||||
## 2. Technical Requirements
|
|
||||||
### Architecture
|
|
||||||
- **Native Bun Server:** Use `Bun.serve()` for high performance.
|
|
||||||
- **Exposure:** The server port must be exposed in `docker-compose.yml` to be accessible outside the container.
|
|
||||||
- **Rendering Strategy:** **Server-Side Rendering (SSR) via Template Literals**.
|
|
||||||
- *Why?* Zero dependencies. No build step (like Vite/Webpack) required. We can simply write functions that return HTML strings.
|
|
||||||
- *Client Side:* Minimal Vanilla JS or a lightweight drop-in library (like HTMX or Alpine from CDN) can be used if interactivity is needed later.
|
|
||||||
|
|
||||||
### File Organization (`src/web/`)
|
|
||||||
We will separate the web infrastructure from game modules to keep concerns clean.
|
|
||||||
- `src/web/server.ts`: Main server class/entry point.
|
|
||||||
- `src/web/router.ts`: Simple routing logic.
|
|
||||||
- `src/web/routes/`: Individual route handlers (e.g., `home.ts`, `health.ts`).
|
|
||||||
- `src/web/views/`: Reusable HTML template functions (Header, Footer, Layouts).
|
|
||||||
- `src/web/public/`: Static assets (CSS, Images) served directly.
|
|
||||||
|
|
||||||
### API / Interface
|
|
||||||
- **GET /health**: Returns `{ status: "ok", uptime: <seconds> }`.
|
|
||||||
- **GET /**: Renders a basic HTML landing page using the View system.
|
|
||||||
|
|
||||||
## 3. Constraints & Validations (CRITICAL)
|
|
||||||
- **Zero Frameworks:** No Express/NestJS.
|
|
||||||
- **Zero Build Tools:** No Webpack/Vite. The code must be runnable directly by `bun run`.
|
|
||||||
- **Docker Integration:** Port 3000 (or env `PORT`) must be mapped in Docker Compose.
|
|
||||||
- **Static Files:** Must implement a handler to check `src/web/public` for file requests.
|
|
||||||
|
|
||||||
## 4. Acceptance Criteria
|
|
||||||
1. [x] `docker-compose up` exposes port 3000.
|
|
||||||
2. [x] `http://localhost:3000` loads a styled HTML page (verifying static asset serving + SSR).
|
|
||||||
3. [x] `http://localhost:3000/health` returns JSON.
|
|
||||||
4. [x] Folder structure established as defined above.
|
|
||||||
|
|
||||||
## 5. Implementation Plan
|
|
||||||
- [x] **Infrastructure**: Create `src/web/` directory structure.
|
|
||||||
- [x] **Core Logic**: Implement `WebServer` class in `src/web/server.ts` with routing and static file serving logic.
|
|
||||||
- [x] **Integration**: Bind `WebServer.start()` to `src/index.ts`.
|
|
||||||
- [x] **Docker**: Update `docker-compose.yml` to map port `3000:3000`.
|
|
||||||
- [x] **Views**: Create a basic `BaseLayout` function in `src/web/views/layout.ts`.
|
|
||||||
- [x] **Env**: Add `PORT` to `config.ts` / `env.ts`.
|
|
||||||
|
|
||||||
## Implementation Notes
|
|
||||||
- Created `src/web` directory with `router.ts`, `server.ts` and subdirectories `routes`, `views`, `public`.
|
|
||||||
- Implemented `WebServer` class using `Bun.serve`.
|
|
||||||
- Added basic CSS and layout system.
|
|
||||||
- Added `PORT` to `src/lib/env.ts` (default 3000).
|
|
||||||
- Integrated into `src/index.ts` to start on boot and graceful shutdown.
|
|
||||||
- Fixed unrelated typing issues in `src/commands/admin/note.ts` and `src/db/indexes.test.ts` to pass strict CI checks.
|
|
||||||
- Verified with `bun test` and `bun x tsc`.
|
|
||||||
Reference in New Issue
Block a user