chore: update docs
This commit is contained in:
166
README.md
166
README.md
@@ -1,52 +1,122 @@
|
|||||||
# bDS2
|
# bDS2
|
||||||
|
|
||||||
bDS2 is the Elixir rewrite of bDS, the offline-first desktop blogging workspace in [../bDS](/Users/gb/Projects/bDS). The repository now contains a substantial BEAM application: Ecto persistence, filesystem-backed content workflows, rendering/generation/publishing pipelines, AI and MCP integrations, and a bundled desktop shell served by the Elixir runtime.
|
bDS2 is the Elixir rewrite of bDS, the offline-first desktop blogging workspace. It is no longer just a rewrite scaffold: the repository now contains the main desktop runtime, Ecto persistence, filesystem-backed content workflows, rendering and publishing pipelines, Lua scripting, AI and MCP integration, and a Phoenix LiveView shell embedded in a native desktop window.
|
||||||
|
|
||||||
The Allium specifications in [specs/](/Users/gb/Projects/bDS2/specs) remain the behavioral contract for the rewrite. For current implementation status and the parity roadmap, see [PLAN.md](/Users/gb/Projects/bDS2/PLAN.md).
|
The Allium specs in [specs/](/Users/gb/Projects/bDS2/specs) remain the behavioral contract for the rewrite. For end-user operation, see [DOCUMENTATION.md](/Users/gb/Projects/bDS2/DOCUMENTATION.md). For the scripting surface, see [API.md](/Users/gb/Projects/bDS2/API.md).
|
||||||
|
|
||||||
## Scope
|
## Current Status
|
||||||
|
|
||||||
The rewrite aims to preserve the product behavior of bDS while replacing the technical stack.
|
The major architectural rework is in place.
|
||||||
|
|
||||||
Behaviour that should remain stable includes:
|
- The desktop UI is served by Phoenix LiveView inside the desktop shell rather than by a separate handwritten frontend runtime.
|
||||||
|
- Assets use Phoenix-default Tailwind and esbuild tooling from [assets/](/Users/gb/Projects/bDS2/assets) into [priv/static/](/Users/gb/Projects/bDS2/priv/static).
|
||||||
|
- Core editorial flows are implemented in the main application: posts, media, tags, templates, scripts, imports, preview, generation, publishing, maintenance, AI, and MCP.
|
||||||
|
- Localization is now a first-class architectural concern rather than an afterthought: UI chrome and rendered site output have separate locale flows, and post/media translation workflows are built into the domain model.
|
||||||
|
|
||||||
- Offline-first editorial workflows.
|
The rewrite still aims to preserve the product behavior of bDS while replacing the technical stack. The contract is product behavior, not the old implementation language or framework choices.
|
||||||
- Filesystem-backed content with stable frontmatter, media sidecars, templates, scripts, and menu formats.
|
|
||||||
- Project, post, media, translation, tag, template, generation, preview, publishing, AI, and MCP workflows.
|
|
||||||
- Generated site output, search behavior, metadata synchronization, and rebuild behavior where those are part of the product contract.
|
|
||||||
|
|
||||||
The following are intentionally not part of the behavioral contract:
|
## Architecture Overview
|
||||||
|
|
||||||
- The implementation language.
|
### Runtime
|
||||||
- Desktop container or UI framework.
|
|
||||||
- ORM choice.
|
|
||||||
- Internal state management, concurrency model, or runtime libraries.
|
|
||||||
|
|
||||||
## Scripting Direction
|
[BDS.Application](/Users/gb/Projects/bDS2/lib/bds/application.ex) is the supervision root. It starts the Phoenix endpoint, database, preview and publishing workers, task supervisors, scripting jobs, and the desktop server/window adapters.
|
||||||
|
|
||||||
bDS2 should use Lua as its user-facing scripting language.
|
At a high level, the stack is:
|
||||||
|
|
||||||
The reason is host fit, not language fashion: Lua has a better embedding story for the BEAM than Python does, while still being small, expressive, and suitable for user-authored macros, transforms, and utility scripts. The current direction is:
|
- Native windowing through the `:desktop` integration.
|
||||||
|
- Phoenix endpoint and LiveView shell for the actual app UI.
|
||||||
|
- Ecto + SQLite for indexed state, editor state, and app data.
|
||||||
|
- Filesystem-backed project data for published content, media, sidecars, scripts, templates, generated output, and rebuild workflows.
|
||||||
|
|
||||||
- Lua script files as the persisted user script format.
|
### Desktop Shell
|
||||||
- A BEAM-hosted execution boundary with explicit host capabilities instead of unrestricted runtime access.
|
|
||||||
- Bounded but long-running script execution for user-authored code, with explicit progress reporting through host APIs.
|
|
||||||
|
|
||||||
The initial runtime baseline in this repository uses a dedicated Elixir scripting boundary with a Luerl-backed Lua adapter. The goal is to keep scripting integration native to the BEAM while making sandboxing and host capability exposure explicit at the application boundary.
|
The desktop workbench lives under [lib/bds/desktop/](/Users/gb/Projects/bDS2/lib/bds/desktop). The main screen is [BDS.Desktop.ShellLive](/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live.ex), with feature-specific editors and sidebar logic under [lib/bds/desktop/shell_live/](/Users/gb/Projects/bDS2/lib/bds/desktop/shell_live).
|
||||||
|
|
||||||
This keeps the scripting surface lightweight and aligned with the Elixir host application. Python remains a possible integration boundary for specialized tasks, but it is no longer the default scripting model for the rewrite.
|
If you are tracing UI behavior, start there first:
|
||||||
|
|
||||||
## Repository Layout
|
- LiveView event routing, workbench state, overlays, and menu handling live in the desktop shell modules.
|
||||||
|
- HEEx templates under the same tree now own most common layout and state styling.
|
||||||
|
- Monaco remains a vendor drop under [priv/ui/monaco/](/Users/gb/Projects/bDS2/priv/ui/monaco).
|
||||||
|
|
||||||
- [mix.exs](/Users/gb/Projects/bDS2/mix.exs): Mix project definition.
|
### Domain Modules
|
||||||
- [config/](/Users/gb/Projects/bDS2/config): Elixir and Ecto configuration.
|
|
||||||
- [lib/](/Users/gb/Projects/bDS2/lib): application bootstrap and shared runtime modules.
|
Most application behavior lives under [lib/bds/](/Users/gb/Projects/bDS2/lib/bds):
|
||||||
- [priv/repo/](/Users/gb/Projects/bDS2/priv/repo): Ecto migrations.
|
|
||||||
- [specs/](/Users/gb/Projects/bDS2/specs): Allium specs distilled from the existing bDS product and being normalized for implementation-agnostic use.
|
- posts, media, tags, templates, scripts, and project settings
|
||||||
|
- metadata, frontmatter, sidecars, rebuild, and maintenance
|
||||||
|
- rendering, generation, preview, and publishing
|
||||||
|
- AI runtimes, chat tooling, embeddings, and MCP
|
||||||
|
- scripting capabilities and generated API docs
|
||||||
|
|
||||||
|
The repo has been pushed toward smaller feature-focused modules rather than one large mixed runtime. For new work, prefer finding the owning feature module instead of adding more behavior to broad catch-all files.
|
||||||
|
|
||||||
|
### Storage Model
|
||||||
|
|
||||||
|
The database is important, but it is not the whole source of truth.
|
||||||
|
|
||||||
|
- Ecto models hold app state, indexes, editor state, and workflow data.
|
||||||
|
- The filesystem holds published content artifacts and sidecar metadata that must stay stable and reviewable.
|
||||||
|
- Rebuild and metadata-diff flows exist because database state and filesystem state are expected to stay in sync.
|
||||||
|
|
||||||
|
When you change persisted behavior, think in both directions: database writes and filesystem writes/readback.
|
||||||
|
|
||||||
|
## Localization And i18n
|
||||||
|
|
||||||
|
Localization now has two separate layers, and confusing them causes bugs.
|
||||||
|
|
||||||
|
### 1. UI Localization
|
||||||
|
|
||||||
|
UI chrome, menus, dashboard text, editor labels, and toasts use Gettext through [BDS.Gettext](/Users/gb/Projects/bDS2/lib/bds/gettext.ex) and the `ui` domain. Locale normalization lives in [BDS.I18n](/Users/gb/Projects/bDS2/lib/bds/i18n.ex), and the desktop shell binds the active UI locale through [BDS.Desktop.UILocale](/Users/gb/Projects/bDS2/lib/bds/desktop/ui_locale.ex).
|
||||||
|
|
||||||
|
In practice, this is the language of the app itself.
|
||||||
|
|
||||||
|
### 2. Render Localization
|
||||||
|
|
||||||
|
Rendered site output uses a separate locale flow. Archive labels, pagination text, template-facing render strings, and generated site language handling use the `render` Gettext domain and the project's `main_language` and `blog_languages` settings.
|
||||||
|
|
||||||
|
In practice, this is the language of the blog output, not necessarily the UI.
|
||||||
|
|
||||||
|
### 3. Content Translation
|
||||||
|
|
||||||
|
Posts and media have translation-aware workflows. Post translations and media metadata translations are modeled explicitly, and generation/preview/publishing use the project's configured languages when building output.
|
||||||
|
|
||||||
|
Relevant translation resources live under:
|
||||||
|
|
||||||
|
- [priv/gettext/](/Users/gb/Projects/bDS2/priv/gettext) for Gettext catalogs
|
||||||
|
- [priv/i18n/](/Users/gb/Projects/bDS2/priv/i18n) for additional locale data used by the app
|
||||||
|
|
||||||
|
If you touch i18n-sensitive behavior, check whether the change belongs to UI locale, render locale, or content translation. They are related, but they are not interchangeable.
|
||||||
|
|
||||||
|
## Frontend And Assets
|
||||||
|
|
||||||
|
Frontend source now follows the Phoenix asset layout:
|
||||||
|
|
||||||
|
- [assets/css/](/Users/gb/Projects/bDS2/assets/css) for Tailwind-based CSS modules
|
||||||
|
- [assets/js/](/Users/gb/Projects/bDS2/assets/js) for LiveView hooks, bridges, Monaco integration, and UI helpers
|
||||||
|
- [priv/static/assets/](/Users/gb/Projects/bDS2/priv/static/assets) for generated outputs
|
||||||
|
|
||||||
|
The rule of thumb is simple:
|
||||||
|
|
||||||
|
- common layout, spacing, state, and typography belong in HEEx and small shared UI primitives
|
||||||
|
- authored CSS stays for tokens and desktop-specific selectors
|
||||||
|
- JavaScript stays focused on LiveView hooks, editor integration, drag/drop, and browser APIs
|
||||||
|
|
||||||
|
## Repository Map
|
||||||
|
|
||||||
|
- [mix.exs](/Users/gb/Projects/bDS2/mix.exs): Mix project definition, aliases, releases, and dependencies
|
||||||
|
- [config/](/Users/gb/Projects/bDS2/config): runtime, dev, test, and asset configuration
|
||||||
|
- [lib/bds/](/Users/gb/Projects/bDS2/lib/bds): core application modules
|
||||||
|
- [lib/bds/desktop/](/Users/gb/Projects/bDS2/lib/bds/desktop): desktop endpoint, shell, menus, controllers, and window integration
|
||||||
|
- [assets/](/Users/gb/Projects/bDS2/assets): Tailwind and esbuild source
|
||||||
|
- [priv/repo/](/Users/gb/Projects/bDS2/priv/repo): Ecto migrations and snapshots
|
||||||
|
- [priv/gettext/](/Users/gb/Projects/bDS2/priv/gettext): UI and render translation catalogs
|
||||||
|
- [specs/](/Users/gb/Projects/bDS2/specs): Allium behavior specs
|
||||||
|
- [DOCUMENTATION.md](/Users/gb/Projects/bDS2/DOCUMENTATION.md): end-user guide
|
||||||
|
- [API.md](/Users/gb/Projects/bDS2/API.md): generated scripting API reference
|
||||||
|
|
||||||
## macOS Development Setup
|
## macOS Development Setup
|
||||||
|
|
||||||
If you are setting up a new macOS machine, start with the toolchain.
|
If you are setting up a new macOS machine, install the toolchain first.
|
||||||
|
|
||||||
### 1. Install Xcode Command Line Tools
|
### 1. Install Xcode Command Line Tools
|
||||||
|
|
||||||
@@ -56,8 +126,6 @@ xcode-select --install
|
|||||||
|
|
||||||
### 2. Install Homebrew
|
### 2. Install Homebrew
|
||||||
|
|
||||||
If Homebrew is not already installed:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||||
```
|
```
|
||||||
@@ -69,36 +137,28 @@ brew update
|
|||||||
brew install erlang elixir sqlite
|
brew install erlang elixir sqlite
|
||||||
```
|
```
|
||||||
|
|
||||||
Verify the installation:
|
### 4. Fetch Dependencies And Set Up The App
|
||||||
|
|
||||||
```bash
|
|
||||||
elixir --version
|
|
||||||
mix --version
|
|
||||||
sqlite3 --version
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Fetch Dependencies
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /Users/gb/Projects/bDS2
|
cd /Users/gb/Projects/bDS2
|
||||||
mix deps.get
|
mix setup
|
||||||
|
mix assets.setup
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5. Create the Local Database
|
## Development Workflow
|
||||||
|
|
||||||
```bash
|
Useful commands:
|
||||||
mix ecto.create
|
|
||||||
mix ecto.migrate
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. Run Tests
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
mix compile --warnings-as-errors
|
||||||
mix test
|
mix test
|
||||||
|
mix dialyzer
|
||||||
|
mix assets.build
|
||||||
```
|
```
|
||||||
|
|
||||||
## Development Notes
|
Notes for developers:
|
||||||
|
|
||||||
- Use `mix test` for validation during development.
|
- Specs in [specs/](/Users/gb/Projects/bDS2/specs) define the intended product behavior.
|
||||||
- The application behavior is defined by the Allium specs in [specs/](/Users/gb/Projects/bDS2/specs).
|
- [DOCUMENTATION.md](/Users/gb/Projects/bDS2/DOCUMENTATION.md) is for end users, not implementation details.
|
||||||
- Use [PLAN.md](/Users/gb/Projects/bDS2/PLAN.md) for implementation status and the parity roadmap.
|
- [API.md](/Users/gb/Projects/bDS2/API.md) is generated from the live scripting capability map and should stay in sync with runtime changes.
|
||||||
|
- When changing persistence or localization behavior, check both the database side and the filesystem/render side before assuming the change is complete.
|
||||||
|
|||||||
577
TAILWIND.md
577
TAILWIND.md
@@ -1,577 +0,0 @@
|
|||||||
# Tailwind And Phoenix Asset Tooling For bDS2 Desktop
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
This document describes the target styling architecture for a Tailwind-integrated Phoenix LiveView desktop app in this repository.
|
|
||||||
|
|
||||||
It is written as a handoff for a coding agent that will perform the implementation.
|
|
||||||
|
|
||||||
This is not a migration guide from a public web app. It is a target-state guide for a Phoenix LiveView desktop shell with local assets, dense editor surfaces, overlays, resizable panes, and desktop-specific titlebar behavior.
|
|
||||||
|
|
||||||
## Verified Current State
|
|
||||||
|
|
||||||
The current app does not use the default Phoenix asset pipeline.
|
|
||||||
|
|
||||||
- CSS is served directly from `priv/ui/app.css`.
|
|
||||||
- JS is served directly from `priv/ui/live.js`.
|
|
||||||
- Static assets are served from `priv/ui` in `lib/bds/desktop/endpoint.ex`.
|
|
||||||
- The root layout links `/assets/app.css` in `lib/bds/desktop/layouts.ex`, but that path is currently backed by `priv/ui/app.css`, not by generated Phoenix assets.
|
|
||||||
- There is no `:tailwind` or `:esbuild` setup in `mix.exs`.
|
|
||||||
|
|
||||||
Relevant files:
|
|
||||||
|
|
||||||
- `lib/bds/desktop/endpoint.ex`
|
|
||||||
- `lib/bds/desktop/layouts.ex`
|
|
||||||
- `mix.exs`
|
|
||||||
- `priv/ui/app.css`
|
|
||||||
- `priv/ui/live.js`
|
|
||||||
|
|
||||||
## Official Phoenix Facts
|
|
||||||
|
|
||||||
The implementation target should follow Phoenix defaults where they fit the desktop shell.
|
|
||||||
|
|
||||||
Official Phoenix references:
|
|
||||||
|
|
||||||
- Phoenix Asset Management: https://hexdocs.pm/phoenix/asset_management.html
|
|
||||||
- Phoenix Components and HEEx: https://hexdocs.pm/phoenix/components.html
|
|
||||||
- Phoenix.Component reference: https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html
|
|
||||||
|
|
||||||
Facts from Phoenix docs and generator templates:
|
|
||||||
|
|
||||||
- Phoenix v1.7+ defaults to Tailwind for CSS and esbuild for JS.
|
|
||||||
- The default CSS source entrypoint is `assets/css/app.css`.
|
|
||||||
- The default generated CSS output is `priv/static/assets/css/app.css`.
|
|
||||||
- The default generated JS output is `priv/static/assets/js/app.js`.
|
|
||||||
- Phoenix promotes function components and HEEx as the main rendering model.
|
|
||||||
- Phoenix does not prescribe per-component CSS modules. Tailwind-first HEEx plus shared source CSS is a valid Phoenix-default shape.
|
|
||||||
|
|
||||||
## Target Outcome
|
|
||||||
|
|
||||||
The target outcome is a solid Phoenix-default asset setup with Tailwind as the main styling system and a generated production stylesheet.
|
|
||||||
|
|
||||||
The target should look like this:
|
|
||||||
|
|
||||||
- Tailwind source lives in `assets/css/app.css` and imported CSS modules.
|
|
||||||
- The final stylesheet is generated into `priv/static/assets/css/app.css`.
|
|
||||||
- LiveView JS entrypoint lives in `assets/js/app.js` and builds to `priv/static/assets/js/app.js`.
|
|
||||||
- The desktop endpoint serves static assets from `priv/static`.
|
|
||||||
- Layouts reference the generated CSS and JS outputs.
|
|
||||||
- HEEx markup carries most layout, spacing, typography, responsive, and state classes.
|
|
||||||
- Authored CSS remains for global tokens, app-region behavior, pseudo-elements, scrollbars, Monaco integration, hard selectors, and overlay mechanics.
|
|
||||||
|
|
||||||
## Architecture Rules
|
|
||||||
|
|
||||||
### 1. Tailwind Owns The Common Case
|
|
||||||
|
|
||||||
Use Tailwind utility classes directly in HEEx for:
|
|
||||||
|
|
||||||
- flex and grid layout
|
|
||||||
- spacing
|
|
||||||
- typography
|
|
||||||
- borders and radii
|
|
||||||
- colors and opacity
|
|
||||||
- active, selected, disabled, and hover states
|
|
||||||
- responsive breakpoints
|
|
||||||
- overflow and truncation
|
|
||||||
|
|
||||||
Do not preserve large semantic wrapper classes when they only encode simple layout decisions.
|
|
||||||
|
|
||||||
Good examples to move into HEEx classes:
|
|
||||||
|
|
||||||
- tab rows
|
|
||||||
- button rows
|
|
||||||
- editor header layout
|
|
||||||
- metadata field layout
|
|
||||||
- sidebar list row spacing
|
|
||||||
- status bar item alignment
|
|
||||||
|
|
||||||
### 2. Authored CSS Owns The Desktop-Specific Case
|
|
||||||
|
|
||||||
Keep authored CSS source files for:
|
|
||||||
|
|
||||||
- `app-region` and `-webkit-app-region`
|
|
||||||
- pseudo-elements used for icons, handles, and active markers
|
|
||||||
- custom scrollbars
|
|
||||||
- Monaco/editor iframe or host integration
|
|
||||||
- absolute overlay stacks and backdrops
|
|
||||||
- drag and drop affordances
|
|
||||||
- complex attribute selectors
|
|
||||||
- hard-to-read repeated combinations that should become shared component classes
|
|
||||||
|
|
||||||
Do not force these into giant utility strings if readability drops.
|
|
||||||
|
|
||||||
### 3. Keep A Thin Semantic CSS Layer
|
|
||||||
|
|
||||||
It is acceptable to keep a small number of semantic component classes when they encode a repeated desktop UI primitive.
|
|
||||||
|
|
||||||
Examples of valid semantic classes in the target state:
|
|
||||||
|
|
||||||
- `.window-titlebar`
|
|
||||||
- `.resizable-panel-divider`
|
|
||||||
- `.overlay-root`
|
|
||||||
- `.monaco-host`
|
|
||||||
- `.panel-entry`
|
|
||||||
- `.btn-base`, `.btn-theme-primary`, `.btn-theme-danger`
|
|
||||||
|
|
||||||
These classes should be implemented in Tailwind source CSS using `@layer components` and should remain small, stable, and reusable.
|
|
||||||
|
|
||||||
### 4. Tokens Must Be Centralized
|
|
||||||
|
|
||||||
The current stylesheet relies heavily on VS Code-like CSS variables. Preserve that idea.
|
|
||||||
|
|
||||||
The new `assets/css/app.css` must define the design tokens once, using Tailwind v4 `@theme` plus any required raw CSS custom properties for runtime-driven values.
|
|
||||||
|
|
||||||
Examples from the current app that must survive:
|
|
||||||
|
|
||||||
- shell/background colors
|
|
||||||
- tab active/inactive colors
|
|
||||||
- status bar colors
|
|
||||||
- focus border color
|
|
||||||
- input background and border colors
|
|
||||||
- sidebar width
|
|
||||||
- assistant width
|
|
||||||
- font family and font size
|
|
||||||
|
|
||||||
### 5. Desktop Layout Constraints Must Stay Intact
|
|
||||||
|
|
||||||
The styling rewrite must preserve these runtime constraints:
|
|
||||||
|
|
||||||
- the app occupies full window width and height
|
|
||||||
- the shell uses `overflow: hidden` at the top level
|
|
||||||
- the main workbench uses `min-height: 0` and `min-width: 0` correctly
|
|
||||||
- resizable sidebars remain width-variable
|
|
||||||
- titlebar remains draggable except for interactive controls
|
|
||||||
- overlays render above the shell without breaking keyboard focus or pointer behavior
|
|
||||||
|
|
||||||
## Proposed Asset Layout
|
|
||||||
|
|
||||||
Use the standard Phoenix asset layout.
|
|
||||||
|
|
||||||
```text
|
|
||||||
assets/
|
|
||||||
css/
|
|
||||||
app.css
|
|
||||||
shell.css
|
|
||||||
sidebar.css
|
|
||||||
tabs.css
|
|
||||||
editor.css
|
|
||||||
forms.css
|
|
||||||
overlays.css
|
|
||||||
panel.css
|
|
||||||
assistant.css
|
|
||||||
menu_editor.css
|
|
||||||
media_editor.css
|
|
||||||
utilities.css
|
|
||||||
js/
|
|
||||||
app.js
|
|
||||||
...
|
|
||||||
priv/
|
|
||||||
static/
|
|
||||||
assets/
|
|
||||||
css/
|
|
||||||
js/
|
|
||||||
```
|
|
||||||
|
|
||||||
Recommended responsibilities:
|
|
||||||
|
|
||||||
- `assets/css/app.css`: Tailwind import, `@source`, tokens, base layer, imports
|
|
||||||
- `assets/css/shell.css`: app shell, titlebar, activity bar, pane shells, status bar
|
|
||||||
- `assets/css/sidebar.css`: sidebar filters, search, chips, calendar tree, load more
|
|
||||||
- `assets/css/tabs.css`: workbench tabs and editor tabs
|
|
||||||
- `assets/css/editor.css`: common editor frame, toolbar, meta column, shared form shell
|
|
||||||
- `assets/css/forms.css`: shared input, textarea, tag chip, picker, inline action primitives
|
|
||||||
- `assets/css/overlays.css`: overlay root, modal backdrop, dialog shells, gallery/lightbox
|
|
||||||
- `assets/css/panel.css`: panel tabs, panel entry cards, tasks, output, git log
|
|
||||||
- `assets/css/assistant.css`: assistant sidebar and chat-specific shared surfaces
|
|
||||||
- `assets/css/menu_editor.css`: menu tree, drag/drop indicators, picker lists
|
|
||||||
- `assets/css/media_editor.css`: media preview, linked post picker, detail forms
|
|
||||||
- `assets/css/utilities.css`: a very small set of custom utilities that are truly reused
|
|
||||||
|
|
||||||
## Proposed Phoenix Asset Tooling
|
|
||||||
|
|
||||||
The implementation should introduce the standard Phoenix aliases and configs.
|
|
||||||
|
|
||||||
### mix.exs
|
|
||||||
|
|
||||||
Add:
|
|
||||||
|
|
||||||
- `{:tailwind, "~> 0.3", runtime: Mix.env() == :dev}`
|
|
||||||
- `{:esbuild, "~> 0.10", runtime: Mix.env() == :dev}`
|
|
||||||
|
|
||||||
Add aliases similar to:
|
|
||||||
|
|
||||||
- `assets.setup`
|
|
||||||
- `assets.build`
|
|
||||||
- `assets.deploy`
|
|
||||||
|
|
||||||
### Versioning (mandatory)
|
|
||||||
|
|
||||||
The Elixir `:tailwind` wrapper still defaults to Tailwind v3. The plan in this document assumes **Tailwind v4** syntax (`@import "tailwindcss"`, `@theme`, `@source`, `@layer components`). Pin both tools explicitly in `config/config.exs`:
|
|
||||||
|
|
||||||
- `config :tailwind, version: "4.1.14"` (or current 4.1.x)
|
|
||||||
- `config :esbuild, version: "0.25.4"` (or current 0.25.x)
|
|
||||||
|
|
||||||
Without an explicit v4 pin the build will silently install Tailwind v3 and v4 directives will not resolve.
|
|
||||||
|
|
||||||
### No Node.js policy
|
|
||||||
|
|
||||||
The Elixir `:tailwind` and `:esbuild` wrappers download self-contained binaries and do **not** require Node.js. The implementation MUST stay Node-free unless a third-party Tailwind plugin is later required (in which case the custom `assets/build.js` route from the Phoenix asset_management guide is used). No `package.json` is added under `assets/`.
|
|
||||||
|
|
||||||
### config/config.exs
|
|
||||||
|
|
||||||
Configure Tailwind input and output paths.
|
|
||||||
|
|
||||||
Target output:
|
|
||||||
|
|
||||||
- `assets/css/app.css` -> `priv/static/assets/css/app.css`
|
|
||||||
|
|
||||||
Configure esbuild for:
|
|
||||||
|
|
||||||
- `assets/js/app.js` -> `priv/static/assets/js/app.js`
|
|
||||||
|
|
||||||
esbuild profile must include `--bundle --target=es2022 --outdir=../priv/static/assets/js --external:/fonts/* --external:/images/*` and `nodePaths: [Mix.Project.build_path() <> "/../../deps"]` so `phoenix`, `phoenix_html`, and `phoenix_live_view` resolve from `deps/` without an `npm install`.
|
|
||||||
|
|
||||||
### config/dev.exs
|
|
||||||
|
|
||||||
Add Phoenix watchers for:
|
|
||||||
|
|
||||||
- Tailwind `--watch`
|
|
||||||
- esbuild `--watch`
|
|
||||||
|
|
||||||
### No phx.digest in desktop builds
|
|
||||||
|
|
||||||
This is a desktop app served through an embedded WebView, not a public web app behind a CDN.
|
|
||||||
|
|
||||||
- Do NOT run `mix phx.digest` as part of `assets.deploy`.
|
|
||||||
- Output filenames stay stable (`app.css`, `app.js`) so the layout can link them by fixed path.
|
|
||||||
- `assets.deploy` for this repo is: `tailwind default --minify`, `esbuild default --minify`. Nothing else.
|
|
||||||
|
|
||||||
### endpoint/layout changes
|
|
||||||
|
|
||||||
Update the desktop endpoint and root layout to serve and link generated assets from `priv/static/assets` instead of `priv/ui`.
|
|
||||||
|
|
||||||
Specifically:
|
|
||||||
|
|
||||||
- Replace the existing `Plug.Static` for `/assets` with `from: {:bds, "priv/static/assets"}` and `only` listing the generated `css` and `js` directories.
|
|
||||||
- Drop the `/vendor/phoenix` and `/vendor/live_view` `Plug.Static` blocks; those scripts are now bundled by esbuild from `deps/`.
|
|
||||||
- Add a dedicated `Plug.Static` for `/monaco` pointing at `priv/ui/monaco` (or move it to `priv/static/monaco`). Monaco is a prebuilt vendor drop and MUST NOT be passed through esbuild.
|
|
||||||
- Remove the `<script src="/vendor/phoenix/...">` and `<script src="/vendor/live_view/...">` tags from `lib/bds/desktop/layouts.ex`. Keep only `/assets/app.css` and `/assets/app.js`.
|
|
||||||
|
|
||||||
## JS Pipeline
|
|
||||||
|
|
||||||
The JS pipeline mirrors the CSS pipeline.
|
|
||||||
|
|
||||||
### Entrypoint
|
|
||||||
|
|
||||||
`assets/js/app.js` is the single esbuild entrypoint. It:
|
|
||||||
|
|
||||||
- imports `phoenix`, `phoenix_html`, and `phoenix_live_view` (resolved from `deps/` via esbuild `nodePaths`)
|
|
||||||
- constructs the `LiveSocket` with the desktop CSRF token
|
|
||||||
- registers all hooks currently defined inline in `priv/ui/live.js`
|
|
||||||
- wires the native menu / titlebar / shortcut bridges
|
|
||||||
|
|
||||||
### Module layout
|
|
||||||
|
|
||||||
Split the current `priv/ui/live.js` (1.4k lines) into focused modules under `assets/js/`:
|
|
||||||
|
|
||||||
- `assets/js/app.js` - entrypoint, LiveSocket, hook registration
|
|
||||||
- `assets/js/hooks/` - one file per hook
|
|
||||||
- `assets/js/bridges/` - native menu, titlebar, shortcut bridges
|
|
||||||
- `assets/js/monaco/` - thin host glue only; do NOT bundle Monaco itself
|
|
||||||
|
|
||||||
### Monaco carve-out
|
|
||||||
|
|
||||||
Monaco is loaded as prebuilt assets from `/monaco/...` and is not part of the esbuild graph. The host glue in `assets/js/monaco/` only configures the loader URL and posts messages; it does not `import` Monaco modules.
|
|
||||||
|
|
||||||
### Vendor stripping
|
|
||||||
|
|
||||||
After the switch:
|
|
||||||
|
|
||||||
- `priv/ui/app.css` is deleted (its content has been redistributed under `assets/css/`).
|
|
||||||
- `priv/ui/live.js` is deleted.
|
|
||||||
- `priv/ui/monaco/` stays (or moves to `priv/static/monaco/`).
|
|
||||||
- The `phoenix` and `phoenix_live_view` dep static drops are no longer served.
|
|
||||||
|
|
||||||
## Iconography
|
|
||||||
|
|
||||||
The app keeps its existing **inline SVG** icon set. Do NOT adopt the Phoenix 1.8 Heroicons-via-Tailwind-plugin pattern.
|
|
||||||
|
|
||||||
Reasons:
|
|
||||||
|
|
||||||
- The target visual look is defined by the current bDS UI; its icons are part of that look.
|
|
||||||
- Inline SVG keeps icons under direct control for sizing, stroke, and currentColor styling via Tailwind utility classes.
|
|
||||||
- Avoiding the Heroicons git dep keeps the build Node-free and dependency-light.
|
|
||||||
|
|
||||||
Rules:
|
|
||||||
|
|
||||||
- Existing SVG icons stay where they are (HEEx components / inline `<svg>` markup).
|
|
||||||
- Icon size and color are controlled by Tailwind utilities on the wrapping element (`size-4`, `text-[var(--color-icon)]`, etc.) using `fill="currentColor"` or `stroke="currentColor"`.
|
|
||||||
- No `:heroicons` mix dep, no Tailwind icon plugin, no `assets/vendor/heroicons.js`.
|
|
||||||
- If a new icon is needed, add the SVG inline in the appropriate component module.
|
|
||||||
|
|
||||||
## HEEx Styling Strategy
|
|
||||||
|
|
||||||
### Prefer Utility Classes In Templates
|
|
||||||
|
|
||||||
Use utility classes in HEEx for:
|
|
||||||
|
|
||||||
- shell flex layout
|
|
||||||
- editor content spacing
|
|
||||||
- section stacks
|
|
||||||
- truncation and overflow
|
|
||||||
- standard button alignment
|
|
||||||
- grid column changes at breakpoints
|
|
||||||
- selected and hovered states that are directly tied to assign state
|
|
||||||
|
|
||||||
### Keep Dynamic Class Lists Explicit
|
|
||||||
|
|
||||||
LiveView templates should build classes with arrays where state is already in assigns.
|
|
||||||
|
|
||||||
Example pattern:
|
|
||||||
|
|
||||||
```elixir
|
|
||||||
class={[
|
|
||||||
"flex items-center gap-2 px-3 py-2 text-sm",
|
|
||||||
selected? && "bg-[var(--color-selected-bg)] text-white",
|
|
||||||
disabled? && "opacity-50 pointer-events-none"
|
|
||||||
]}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Do Not Hide Structure Behind Giant Custom Class Trees
|
|
||||||
|
|
||||||
Avoid re-creating the current `app.css` by keeping every nested selector and merely moving it into `assets/css`.
|
|
||||||
|
|
||||||
If a selector exists only because the old CSS owned all layout, move that responsibility into HEEx.
|
|
||||||
|
|
||||||
## Tailwind Source Conventions
|
|
||||||
|
|
||||||
### app.css
|
|
||||||
|
|
||||||
`assets/css/app.css` should use Tailwind v4 import syntax.
|
|
||||||
|
|
||||||
`source(none)` disables Tailwind's automatic content detection so only directories listed via `@source` are scanned. Every directory that ships HEEx or class strings MUST be listed. Audit `lib/` for additional renderers (preview, generation, MCP surfaces) and add `@source` lines for any that emit class names consumed at build time.
|
|
||||||
|
|
||||||
Runtime-driven values (e.g. resizable panel widths that change via CSS variable assignment from JS) MUST stay as plain CSS custom properties under `:root` or a scoped selector. `@theme` values are baked at build time and are not appropriate for values mutated at runtime. Use `@theme` for stable design tokens (colors, font sizes, spacing scale extensions) that should produce utility classes; use `:root { --foo: … }` for everything that the app writes to at runtime.
|
|
||||||
|
|
||||||
Suggested structure:
|
|
||||||
|
|
||||||
```css
|
|
||||||
@import "tailwindcss" source(none);
|
|
||||||
|
|
||||||
@source "../css";
|
|
||||||
@source "../js";
|
|
||||||
@source "../../lib/bds/desktop";
|
|
||||||
|
|
||||||
@theme {
|
|
||||||
/* app tokens */
|
|
||||||
}
|
|
||||||
|
|
||||||
@layer base {
|
|
||||||
/* html, body, root shell defaults */
|
|
||||||
}
|
|
||||||
|
|
||||||
@import "./shell.css";
|
|
||||||
@import "./sidebar.css";
|
|
||||||
@import "./tabs.css";
|
|
||||||
@import "./editor.css";
|
|
||||||
@import "./forms.css";
|
|
||||||
@import "./panel.css";
|
|
||||||
@import "./assistant.css";
|
|
||||||
@import "./overlays.css";
|
|
||||||
@import "./menu_editor.css";
|
|
||||||
@import "./media_editor.css";
|
|
||||||
@import "./utilities.css";
|
|
||||||
```
|
|
||||||
|
|
||||||
### Component CSS Rules
|
|
||||||
|
|
||||||
When writing component CSS in imported files:
|
|
||||||
|
|
||||||
- use `@layer components` for shared semantic classes
|
|
||||||
- use `@layer utilities` only for narrowly reusable custom utilities
|
|
||||||
- keep selectors shallow
|
|
||||||
- avoid giant descendant chains unless required by generated HTML structure or overlay mechanics
|
|
||||||
- prefer `@apply` sparingly and only for stable component classes, not as a substitute for writing HEEx utilities
|
|
||||||
|
|
||||||
## Current UI Structure Reference
|
|
||||||
|
|
||||||
The implementation agent must use the current monolith as a source map, not as the final architecture.
|
|
||||||
|
|
||||||
The current stylesheet is `priv/ui/app.css` and is approximately 8.5k lines.
|
|
||||||
|
|
||||||
Use the following region map when carrying styling over.
|
|
||||||
|
|
||||||
### Current app.css region map
|
|
||||||
|
|
||||||
- Lines `1-140`: root variables, base element reset, buttons, top-level shell defaults
|
|
||||||
- Lines `141-415`: app shell and window titlebar
|
|
||||||
- `.app`, `.app-main`, `.app-content`
|
|
||||||
- `.window-titlebar*`
|
|
||||||
- Lines `416-623`: activity bar and sidebar shells
|
|
||||||
- `.activity-bar*`
|
|
||||||
- `.sidebar-shell*`, `.assistant-sidebar-shell*`
|
|
||||||
- `.sidebar*`, `.assistant-sidebar*`
|
|
||||||
- `.resizable-panel-divider`
|
|
||||||
- Lines `624-812`: workbench tab bar
|
|
||||||
- `.tab-bar*`, `.tab*`
|
|
||||||
- Lines `813-1100`: shared editor shell and editor tabs
|
|
||||||
- `.editor-shell`, `.editor-frame`, `.editor-main`, `.editor-meta`
|
|
||||||
- `.editor-toolbar*`
|
|
||||||
- `.post-editor .editor-header`, `.editor-tabs`, `.editor-tab*`
|
|
||||||
- Lines `1100-1700`: post editor forms and metadata/media panel
|
|
||||||
- `.post-editor .editor-content`
|
|
||||||
- `.post-editor .editor-field*`
|
|
||||||
- `.post-editor .post-editor-input`, `.post-editor-textarea`
|
|
||||||
- `.tag-input*`, `.tag-chip*`
|
|
||||||
- media insertion and post media list
|
|
||||||
- Line `1691` onward: first responsive collapse for editor/media layout
|
|
||||||
- Lines `1736-1833`: early shell/gallery overlay and insert-media grid rules
|
|
||||||
- Lines `1833+`: more mobile/narrow viewport adjustments
|
|
||||||
- Lines `1950-2263`: status bar and shell footer controls
|
|
||||||
- `.status-bar*`
|
|
||||||
- `.project-selector*`
|
|
||||||
- Lines `2264-2599`: overlay root and modal system
|
|
||||||
- `.overlay-root`
|
|
||||||
- `.ai-suggestions-modal*`
|
|
||||||
- `.insert-modal*`
|
|
||||||
- `.language-picker-modal*`
|
|
||||||
- `.confirm-delete-modal*`
|
|
||||||
- `.gallery-overlay*`
|
|
||||||
- Lines `2600-2876`: menu editor
|
|
||||||
- `.menu-editor-*`
|
|
||||||
- Lines `2889+`: media editor
|
|
||||||
- `[data-testid="media-editor"] *`
|
|
||||||
- Lines `3458+`: style/theme picker surface
|
|
||||||
- `.style-theme-*`
|
|
||||||
- Lines `4958`, `6722`, `8268`, `8514`: later breakpoint-specific adjustments for desktop shell and advanced editors
|
|
||||||
|
|
||||||
Treat those ranges as source material to be redistributed into the new Tailwind source layout.
|
|
||||||
|
|
||||||
## Current HEEx And Component Surface Reference
|
|
||||||
|
|
||||||
The styling rewrite needs to move with the component structure, not only with CSS selectors.
|
|
||||||
|
|
||||||
Important current rendering surfaces:
|
|
||||||
|
|
||||||
- `lib/bds/desktop/shell_live.ex`
|
|
||||||
- top-level workbench render entry
|
|
||||||
- `lib/bds/desktop/shell_live/sidebar_components.ex`
|
|
||||||
- sidebar search, archive tree, tag/category chips, nav/settings lists, load more
|
|
||||||
- `lib/bds/desktop/shell_live/panel_renderer.ex`
|
|
||||||
- tasks, output, git log, panel toolbars
|
|
||||||
- `lib/bds/desktop/shell_live/post_editor.ex`
|
|
||||||
- post editor render surface
|
|
||||||
- `lib/bds/desktop/shell_live/media_editor.ex`
|
|
||||||
- media editor render surface
|
|
||||||
- `lib/bds/desktop/shell_live/script_editor.ex`
|
|
||||||
- script editor render surface
|
|
||||||
- `lib/bds/desktop/shell_live/template_editor.ex`
|
|
||||||
- template editor render surface
|
|
||||||
- `lib/bds/desktop/shell_live/chat_editor.ex`
|
|
||||||
- assistant/chat surface
|
|
||||||
- `lib/bds/desktop/shell_live/menu_editor.ex`
|
|
||||||
- menu editor tree surface
|
|
||||||
|
|
||||||
Implementation rule:
|
|
||||||
|
|
||||||
- move simple layout and state styling into these HEEx/component surfaces
|
|
||||||
- keep authored CSS for shared primitives and complex desktop behavior
|
|
||||||
|
|
||||||
## Desktop-Specific Styling Rules
|
|
||||||
|
|
||||||
The app is a desktop shell, not a normal browser page.
|
|
||||||
|
|
||||||
The implementation must preserve:
|
|
||||||
|
|
||||||
- draggable titlebar regions
|
|
||||||
- non-draggable controls inside the titlebar
|
|
||||||
- local, app-like split-pane behavior
|
|
||||||
- fixed-height titlebar, tabs, and status bar rails
|
|
||||||
- overlay stacking over the shell
|
|
||||||
- editor and sidebar widths controlled by CSS variables where appropriate
|
|
||||||
- visual parity for assistant/sidebar/panel open and closed states
|
|
||||||
|
|
||||||
Do not optimize for tiny public web payloads at the expense of shell clarity.
|
|
||||||
Do optimize for maintainability, explicit component ownership, and predictable desktop behavior.
|
|
||||||
|
|
||||||
## Implementation Phases
|
|
||||||
|
|
||||||
### Phase 0: Tests And Validation Baseline
|
|
||||||
|
|
||||||
- Add a smoke test that requests `/assets/app.css` and `/assets/app.js` and asserts a 200 with non-empty body served from `priv/static/assets`.
|
|
||||||
- Add a render snapshot test for the top-level shell HEEx so class-string regressions during the rewrite are caught.
|
|
||||||
- Establish that every phase ends with clean `mix compile --warnings-as-errors`, `mix test`, and `mix dialyzer` runs (per repo AGENTS.md).
|
|
||||||
|
|
||||||
### Phase 1: Install Phoenix Asset Tooling
|
|
||||||
|
|
||||||
- add Tailwind and esbuild dependencies
|
|
||||||
- create `assets/css/app.css` and `assets/js/app.js`
|
|
||||||
- configure `config/config.exs`, `config/dev.exs`, and `mix.exs`
|
|
||||||
- switch endpoint/layouts to generated assets
|
|
||||||
- keep current visuals as close as possible
|
|
||||||
|
|
||||||
### Phase 2: Split The Monolith Into Source Modules
|
|
||||||
|
|
||||||
- move the current `priv/ui/app.css` into the proposed `assets/css/*.css` modules
|
|
||||||
- keep selectors mostly intact at first
|
|
||||||
- copy raw selectors only; do NOT rewrite to `@apply` in this phase
|
|
||||||
- defer all `@apply` and utility-extraction decisions to Phase 3
|
|
||||||
- verify the desktop shell still renders correctly
|
|
||||||
|
|
||||||
### Phase 3: Move Common Layout Into HEEx
|
|
||||||
|
|
||||||
- rewrite top-level shell markup, tabs, headers, and common forms to use Tailwind classes directly
|
|
||||||
- reduce selector nesting
|
|
||||||
- keep only the thin semantic CSS layer
|
|
||||||
|
|
||||||
### Phase 4: Normalize Shared Primitives
|
|
||||||
|
|
||||||
- standardize buttons
|
|
||||||
- standardize inputs and textareas
|
|
||||||
- standardize tabs and badges
|
|
||||||
- standardize panel entries and empty states
|
|
||||||
|
|
||||||
### Phase 5: Finish Desktop-Specific Surfaces
|
|
||||||
|
|
||||||
- overlays
|
|
||||||
- menu editor drag/drop states
|
|
||||||
- media preview/detail layouts
|
|
||||||
- assistant/chat surfaces
|
|
||||||
- narrow viewport behavior
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
|
|
||||||
The rewrite is successful when:
|
|
||||||
|
|
||||||
- assets are built through Phoenix default tooling
|
|
||||||
- the desktop endpoint serves generated assets from `priv/static`
|
|
||||||
- the visual shell matches the existing app closely enough for feature work to continue
|
|
||||||
- the current `priv/ui/app.css` is no longer the source of truth
|
|
||||||
- the new styling is split into source modules with clear ownership
|
|
||||||
- HEEx markup owns common layout and state classes
|
|
||||||
- authored CSS is limited to tokens, desktop primitives, and complex selectors
|
|
||||||
- Tailwind v4 and esbuild versions are explicitly pinned in `config/config.exs`
|
|
||||||
- no Node.js / `package.json` is introduced under `assets/`
|
|
||||||
- no `mix phx.digest` step exists; generated asset filenames remain stable
|
|
||||||
- inline SVG iconography from the existing UI is preserved (no Heroicons dep)
|
|
||||||
- `mix compile --warnings-as-errors`, `mix test`, and `mix dialyzer` are clean after every phase
|
|
||||||
|
|
||||||
## Non-Goals
|
|
||||||
|
|
||||||
These are not goals of the rewrite:
|
|
||||||
|
|
||||||
- blindly replacing every old class with utilities in one pass
|
|
||||||
- preserving the exact old selector tree
|
|
||||||
- introducing CSS modules or a React-style styling system
|
|
||||||
- optimizing for generic web landing-page concerns
|
|
||||||
- changing product behavior unrelated to styling and asset delivery
|
|
||||||
|
|
||||||
## Guidance For The Coding Agent
|
|
||||||
|
|
||||||
When implementing this plan:
|
|
||||||
|
|
||||||
- start by wiring Phoenix asset tooling, not by rewriting 8k lines of CSS in place
|
|
||||||
- preserve runtime behavior first, then simplify
|
|
||||||
- move layout decisions to HEEx only when they become clearer there
|
|
||||||
- keep desktop-specific mechanics in CSS
|
|
||||||
- use the current `priv/ui/app.css` region map as a source index, not as a blueprint for the final architecture
|
|
||||||
Reference in New Issue
Block a user