Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
6cb6076
Upgrade Angular to v21 and migrate to new control flow syntax
correct-horse-battery-bench May 13, 2026
2bab51b
Upgrade @fortawesome/angular-fontawesome to v4
correct-horse-battery-bench May 13, 2026
702b742
Remove unused @ngrx/store, pin jsona, add lint:tokens script
correct-horse-battery-bench May 13, 2026
4d15797
Wire app-level UX defaults and module cleanup
correct-horse-battery-bench May 13, 2026
25cb47a
Split routing-free sibling modules for home and tasks
correct-horse-battery-bench May 13, 2026
3e4a0cc
Improve table rendering: isNumeric columns, task status icons, delete…
correct-horse-battery-bench May 13, 2026
6209b22
Apply design-system follow-through and small TS adjustments
correct-horse-battery-bench May 13, 2026
f5f07f2
Switch from Angular Material 2 to Material 3
correct-horse-battery-bench May 13, 2026
0f82e48
Migrate design system to CSS variables and design tokens
correct-horse-battery-bench May 13, 2026
a77493c
Update layouts: header, page header, form row, responsive system
correct-horse-battery-bench May 13, 2026
6e7a806
Add Storybook with component stories and theme integration
correct-horse-battery-bench May 13, 2026
555f669
Remove custom hashlist container -> better to pass the suffix as child
correct-horse-battery-bench May 15, 2026
bd0adec
Add readonly and linkTo support to shared input components
correct-horse-battery-bench May 15, 2026
e6a493d
Replace simulate-form-field shells with readonly input components
correct-horse-battery-bench May 15, 2026
2b4fb88
Hoist task action buttons into input matSuffix slots
correct-horse-battery-bench May 15, 2026
2d0409b
Theme task-visual graph colors via CSS tokens
correct-horse-battery-bench May 15, 2026
1d1b78a
Right-align stepper action buttons in new-agent flow
correct-horse-battery-bench May 15, 2026
4fe515c
Sync package-lock.json with installed dependencies
correct-horse-battery-bench May 15, 2026
a3d4400
Revert task-visual color theming (canvas is unused)
correct-horse-battery-bench May 15, 2026
082d736
Extract per-theme color tokens into light.scss and dark.scss
correct-horse-battery-bench May 15, 2026
0352afc
Center help and pretasks dialogs by capping width
correct-horse-battery-bench May 15, 2026
ffb7ddc
Left-align new-agent stepper actions and use secondary Back button
correct-horse-battery-bench May 15, 2026
07d0113
Isolate multiselect matSuffix slot from autocomplete clicks
correct-horse-battery-bench May 15, 2026
0db987e
Cap new-task cheatsheet dialog width
correct-horse-battery-bench May 15, 2026
c21a7a6
Use --popover token for Material dialog containers
correct-horse-battery-bench May 15, 2026
a5982d7
Release compact-form height clamps for textarea form fields
correct-horse-battery-bench May 15, 2026
eccc3b0
Polish stepper header hover and focus indicators
correct-horse-battery-bench May 15, 2026
2bc1a71
Add align="left" mode to form-row for content-width clusters
correct-horse-battery-bench May 15, 2026
5768440
Use form-row align="left" for checkbox clusters
correct-horse-battery-bench May 15, 2026
9efa9e4
Add app-divider atom and replace raw <hr> usages
correct-horse-battery-bench May 15, 2026
ce4463c
Collapse blacklisted-attack wrapper via display: contents
correct-horse-battery-bench May 15, 2026
786347f
Clamp dynamic form labels and tooltip on overflow
correct-horse-battery-bench May 15, 2026
ae3a19e
Clamp shared input labels via overflow tooltip
correct-horse-battery-bench May 15, 2026
77b9af6
Migrate dynamic form to shared input components
correct-horse-battery-bench May 15, 2026
c6a4112
Simplify overflow-tooltip to measure host element only
correct-horse-battery-bench May 15, 2026
c0d8bed
Add fullWidth opt-in for dynamic form cells
correct-horse-battery-bench May 15, 2026
79483fa
Refine header brand sizing and dark-mode logo backdrop
correct-horse-battery-bench May 15, 2026
fee0089
Bump page-subtitle to text-xl
correct-horse-battery-bench May 15, 2026
fa12168
Add showPageWrapper opt-out to dynamic form
correct-horse-battery-bench May 15, 2026
a104051
Step dynamic-form section title down to --text-sm
correct-horse-battery-bench May 15, 2026
fda5dfc
Wrap Settings form in app-page with shared title
correct-horse-battery-bench May 15, 2026
45b2941
Use page-subtitle in server-actions component
correct-horse-battery-bench May 15, 2026
daa468e
Get rid of ng deep and rigrously extract
correct-horse-battery-bench May 15, 2026
00d95c7
Cleanup comments
correct-horse-battery-bench May 15, 2026
3ea6689
new theme for fallout added to the new theme ui
coiseiw May 20, 2026
0dedd54
Integration of dynamic custom theme together with a readme on how to …
coiseiw May 22, 2026
de14f29
No cache for the css cache to avoid issue when adding a new .css file
coiseiw May 22, 2026
da6e41e
update the custom theme to integrate image in the folder custom
coiseiw May 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 2 additions & 1 deletion .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ services:
# This is where VS Code should expect to find your project's source code
# and the value of "workspaceFolder" in .devcontainer/devcontainer.json
- ..:/app
- ../custom-themes:/custom-themes:ro
networks:
- hashtopolis_dev

networks:
hashtopolis_dev:
# This network will also be used by the python-agent
name: hashtopolis_dev
name: hashtopolis_dev
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ git-version.json
# Config file
config.json
.devcontainer/.env

*storybook.log
storybook-static
9 changes: 9 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { StorybookConfig } from '@storybook/angular';

const config: StorybookConfig = {
stories: ['../src/stories/**/*.stories.@(js|ts)'],
addons: ['@storybook/addon-a11y', '@storybook/addon-docs'],
framework: '@storybook/angular',
staticDirs: ['../src/assets']
};
export default config;
1 change: 1 addition & 0 deletions .storybook/preview-head.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script>document.body.classList.add('light-theme');</script>
75 changes: 75 additions & 0 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { applicationConfig, type Preview } from '@storybook/angular';
import { provideAnimations } from '@angular/platform-browser/animations';
import { provideHttpClient } from '@angular/common/http';
import { provideRouter } from '@angular/router';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';

// Styles (tailwind.css + styles.scss) are inherited from the angular build target
// via browserTarget in angular.json — do NOT import them here, or Storybook's
// webpack CSS pipeline tries to re-process them without the @tailwindcss/postcss plugin.

import { registerEChartsModules } from '../src/app/shared/graphs/echarts/echarts.config';
registerEChartsModules();

const stubbedActivatedRoute = {
snapshot: {
params: {},
queryParams: {},
data: {},
url: [],
paramMap: { get: () => null, getAll: () => [], has: () => false, keys: [] },
queryParamMap: { get: () => null, getAll: () => [], has: () => false, keys: [] }
},
params: of({}),
queryParams: of({}),
data: of({}),
url: of([]),
fragment: of(null),
paramMap: of({ get: () => null, getAll: () => [], has: () => false, keys: [] }),
queryParamMap: of({ get: () => null, getAll: () => [], has: () => false, keys: [] })
};

const preview: Preview = {
globalTypes: {
theme: {
description: 'Theme',
defaultValue: 'light',
toolbar: {
title: 'Theme',
icon: 'paintbrush',
items: [
{ value: 'light', title: 'Light', icon: 'sun' },
{ value: 'dark', title: 'Dark', icon: 'moon' }
],
dynamicTitle: true
}
}
},
decorators: [
(storyFn, ctx) => {
const theme = (ctx.globals['theme'] as string) ?? 'light';
document.body.classList.toggle('light-theme', theme === 'light');
document.body.classList.toggle('dark-theme', theme === 'dark');
return storyFn();
},
applicationConfig({
providers: [
provideAnimations(),
provideRouter([]),
provideHttpClient(),
{ provide: ActivatedRoute, useValue: stubbedActivatedRoute }
]
})
],
parameters: {
layout: 'centered',
backgrounds: { disable: true },
controls: {
expanded: true,
matchers: { color: /(background|color)$/i, date: /Date$/i }
}
}
};

export default preview;
16 changes: 16 additions & 0 deletions .storybook/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "../tsconfig.app.json",
"compilerOptions": {
"types": ["node"],
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"moduleResolution": "bundler"
},
"exclude": ["../src/test.ts", "../src/**/*.spec.ts"],
"include": [
"../src/polyfills.ts",
"../src/stories/**/*",
"./preview.ts"
],
"files": ["./typings.d.ts"]
}
7 changes: 7 additions & 0 deletions .storybook/typings.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
declare module '*.md' {
const content: string;
export default content;
}

declare module 'pdfmake/build/pdfmake';
declare module 'pdfmake/build/vfs_fonts';
1 change: 0 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ COPY docker-entrypoint.sh /usr/local/bin
# BUILD Image
#----BEGIN----
FROM hashtopolis-web-ui-base AS hashtopolis-web-ui-build
# Coping the app into the container
COPY . ./

# npm package - clean install
Expand Down
18 changes: 18 additions & 0 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,24 @@
"src/**/*.html"
]
}
},
"storybook": {
"builder": "@storybook/angular:start-storybook",
"options": {
"configDir": ".storybook",
"browserTarget": "hashtopolis:build",
"compodoc": false,
"port": 6006
}
},
"build-storybook": {
"builder": "@storybook/angular:build-storybook",
"options": {
"configDir": ".storybook",
"browserTarget": "hashtopolis:build",
"compodoc": false,
"outputDir": "dist/storybook"
}
}
}
}
Expand Down
195 changes: 195 additions & 0 deletions custom-themes/HOW_TO_CREATE_CUSTOM_THEME.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# Custom Theme Authoring Guide

This project supports runtime custom themes from CSS files.

For normal usage, custom theme creation is intentionally low-complexity: add one CSS file and recreate the container.

## 1) Add theme files

Place a `.css` file in the `custom-themes` folder.
If needed, place related assets in the same folder (for example logo images).

Examples:

- `custom-themes/ocean.css`
- `custom-themes/cyber-night.css`

The file name is converted to the theme id using lowercase kebab-case.

- `Ocean Night.css` -> `ocean-night`

## 2) Define your theme scope

Use the generated id as a body class in the format `.<theme-id>-theme`.

Example for `ocean.css`:

```css
.ocean-theme {
--background: #07131f;
--foreground: #d9f2ff;
--primary: #4db5ff;
--border: rgba(77, 181, 255, 0.35);
color-scheme: dark;
}
```

At minimum, define the color tokens your components rely on.

## 3) Recreate container

When the container starts, `docker-entrypoint.sh` scans `custom-themes`, copies CSS files into served assets, and generates a manifest.

Apply changes with:

```bash
docker compose up -d --build --force-recreate
```

If your stack is already running and mounted correctly, a restart may be enough:

```bash
docker compose restart
```

## 4) Verify in browser

Open:

- `/assets/themes/custom-themes.json`
- `/assets/custom-themes/<theme-id>.css`

If your theme uses local assets, also verify:

- `/assets/custom-themes/<asset-file-name>`

If both are available, the theme appears in theme selectors.

## Notes

- Custom theme ids must match `^[a-z0-9-]+$`.
- Built-in ids are reserved and ignored in custom manifest: `light`, `dark`, `fallout`.
- Use absolute URLs in CSS for assets. For custom-theme local assets, use `/assets/custom-themes/...`.
- Custom menu icons are currently generated as `style` by default.
- Do not add JavaScript or TypeScript to create a theme unless you are extending platform behavior.

## LLM Prompt Template

Copy and adapt this prompt when asking an LLM to generate a new theme CSS file.

```text
Generate a single CSS file for a Hashtopolis custom theme.

Requirements:
- Output CSS only, no markdown.
- Use this class selector exactly: .<theme-id>-theme
- Define all variables below with visually coherent values:
--background
--muted
--well
--card
--card-hover
--input
--sidebar
--foreground
--muted-foreground
--subtle-foreground
--heading-foreground
--primary
--primary-hover
--primary-muted
--primary-foreground
--secondary
--border
--border-strong
--border-faint
--surface-faint
--surface-soft
--surface-soft-hover
--cell-hover
--success
--warning
--destructive
--info
--link
--link-hover
--success-bg
--destructive-bg
--info-bg
--header
--shell-frame-image
--brand-backdrop
--shadow-sm
--shadow-md
--shadow-lg
--gradient-accent
- Include color-scheme: dark; or color-scheme: light; to match the palette.
- Keep contrast accessible for body text and headings.
- Avoid changing any selector outside .<theme-id>-theme.

Theme request:
- Theme id: <theme-id>
- Mood/style: <describe visual direction>
- Preferred primary hue: <color>
- Dark or light: <dark|light>
```

## Example Output

This is the kind of CSS structure the prompt should generate.

```css
.ocean-night-theme {
--background: #06131f;
--muted: #0d1d2c;
--well: #10263a;
--card: rgba(255, 255, 255, 0.05);
--card-hover: rgba(255, 255, 255, 0.09);
--input: rgba(255, 255, 255, 0.06);
--sidebar: #081520;

--foreground: #e6f4ff;
--muted-foreground: rgba(230, 244, 255, 0.75);
--subtle-foreground: rgba(230, 244, 255, 0.55);
--heading-foreground: #ffffff;

--primary: #4db5ff;
--primary-hover: #7ac8ff;
--primary-muted: rgba(77, 181, 255, 0.2);
--primary-foreground: #04111b;
--secondary: #7df9ff;

--border: rgba(77, 181, 255, 0.25);
--border-strong: rgba(77, 181, 255, 0.45);
--border-faint: rgba(77, 181, 255, 0.15);

--surface-faint: rgba(255, 255, 255, 0.03);
--surface-soft: rgba(255, 255, 255, 0.06);
--surface-soft-hover: rgba(255, 255, 255, 0.1);

--cell-hover: rgba(77, 181, 255, 0.16);

--success: #76e39b;
--warning: #ffd26a;
--destructive: #ff7f96;
--info: #7df9ff;
--link: #7df9ff;
--link-hover: #b7fdff;

--success-bg: color-mix(in oklch, var(--success) 18%, var(--well));
--destructive-bg: color-mix(in oklch, var(--destructive) 18%, var(--well));
--info-bg: color-mix(in oklch, var(--info) 18%, var(--well));

--header: rgba(6, 19, 31, 0.72);
--shell-frame-image: linear-gradient(135deg, rgba(77, 181, 255, 0.18), rgba(125, 249, 255, 0.08));
--brand-backdrop: #4db5ff;

--shadow-sm: none;
--shadow-md: 0 3px 12px rgba(3, 11, 20, 0.42);
--shadow-lg: 0 10px 30px rgba(3, 11, 20, 0.58);

--gradient-accent: linear-gradient(130deg, #4db5ff 0%, #7df9ff 100%);

color-scheme: dark;
}
```
Loading