# sanctum-web Layout Redesign Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Fork stoatchat/for-web into sanctum-web, fix the root layout so the message area fills the screen properly, and deploy it to mithraic.space/app via Forgejo CI. **Architecture:** The root layout lives in two files — `Interface.tsx` (the grid shell) and `Sidebar.tsx` (server list + channel list). Both use Panda CSS (`styled-system/jsx`). We replace the loose flex layout with an explicit CSS Grid, add `min-width: 0` guards on grid children, and wire up a Forgejo Actions pipeline that builds and rsyncs to the VPS on every push to main. **Tech Stack:** Solid.js, Vite, TypeScript, Panda CSS (`styled-system/jsx`), pnpm monorepo, Forgejo Actions, rsync --- ## File Map | Action | Path | Purpose | |---|---|---| | Clone | `git.mithraic.cloud/ad3laid3/sanctum-web` | The fork (already created) | | Modify | `packages/client/src/Interface.tsx` | Root grid shell — Layout + Content styled components | | Modify | `packages/client/src/interface/Sidebar.tsx` | Server list + channel list sizing | | Create | `.forgejo/workflows/deploy.yml` | CI: build + rsync to VPS on push to main | | Create | `packages/client/.env` | API URLs pointing at mithraic.space services | --- ## Task 1: Clone the fork and add upstream remote **Files:** - Working directory: wherever you keep projects locally - [ ] **Step 1: Clone the fork** ```bash git clone https://git.mithraic.cloud/ad3laid3/sanctum-web cd sanctum-web ``` - [ ] **Step 2: Add the upstream so you can pull fixes from stoatchat later** ```bash git remote add upstream https://github.com/stoatchat/for-web git fetch upstream ``` - [ ] **Step 3: Install dependencies** ```bash pnpm install ``` - [ ] **Step 4: Confirm dev server starts** ```bash cd packages/client pnpm dev ``` Expected: Vite dev server starts, browser opens the app (will show login screen since no backend is configured yet — that's fine). - [ ] **Step 5: Commit the baseline (upstream content as-is)** ```bash cd ../.. git add . git commit -m "chore: initial fork from stoatchat/for-web" git push origin main ``` --- ## Task 2: Configure environment for mithraic.space **Files:** - Create: `packages/client/.env` - [ ] **Step 1: Create the env file** ```bash cat > packages/client/.env << 'EOF' VITE_API_URL=https://mithraic.space/api VITE_WS_URL=wss://mithraic.space/ws VITE_MEDIA_URL=https://mithraic.space/media VITE_PROXY_URL=https://mithraic.space/proxy EOF ``` - [ ] **Step 2: Confirm build succeeds with these env vars** ```bash cd packages/client pnpm build ``` Expected: `dist/` folder is created with no errors. - [ ] **Step 3: Commit** ```bash cd ../.. git add packages/client/.env git commit -m "chore: configure env for mithraic.space" git push origin main ``` --- ## Task 3: Fix the root layout in Interface.tsx **Files:** - Modify: `packages/client/src/Interface.tsx` The current `Layout` uses `display: flex` with no explicit column widths, and `Content` uses `width: 100%` which doesn't fill remaining space properly in a flex context. The fix: switch Layout to CSS Grid with `auto 1fr` columns, and replace `width: 100%` on Content with `minWidth: 0` so it respects the grid. - [ ] **Step 1: Open `packages/client/src/Interface.tsx` and find the two styled components at the bottom of the file** They look like this: ```typescript const Layout = styled("div", { base: { display: "flex", height: "100%", minWidth: 0, }, // ... }); const Content = styled("div", { base: { background: "var(--md-sys-color-surface-container-low)", display: "flex", width: "100%", minWidth: 0, }, // ... }); ``` - [ ] **Step 2: Replace `Layout` base styles — switch from flex to grid** Change the `Layout` styled component's `base` to: ```typescript const Layout = styled("div", { base: { display: "grid", gridTemplateColumns: "auto 1fr", height: "100%", overflow: "hidden", }, variants: { disconnected: { true: { color: "var(--md-sys-color-on-primary-container)", background: "var(--md-sys-color-primary-container)", }, false: { color: "var(--md-sys-color-outline)", background: "var(--md-sys-color-surface-container-high)", }, }, }, }); ``` - [ ] **Step 3: Replace `Content` base styles — remove width:100%, add minWidth:0** ```typescript const Content = styled("div", { base: { background: "var(--md-sys-color-surface-container-low)", display: "flex", minWidth: 0, overflow: "hidden", }, variants: { sidebar: { false: { borderTopLeftRadius: "var(--borderRadius-lg)", borderBottomLeftRadius: "var(--borderRadius-lg)", overflow: "hidden", }, }, }, }); ``` - [ ] **Step 4: Start the dev server and verify the message area now fills the screen** ```bash cd packages/client && pnpm dev ``` Expected: The message area takes up the majority of the window. Sidebar stays on the left without overflowing. - [ ] **Step 5: Commit** ```bash cd ../.. git add packages/client/src/Interface.tsx git commit -m "fix: switch root layout to CSS Grid, message area fills remaining space" git push origin main ``` --- ## Task 4: Fix Sidebar panel widths **Files:** - Modify: `packages/client/src/interface/Sidebar.tsx` The Sidebar wraps both the server icon list and the channel list in a single `display: flex` div. We need to give each child an explicit width so they never squeeze or overflow. - [ ] **Step 1: Open `packages/client/src/interface/Sidebar.tsx` and find the root return statement** It looks like: ```typescript return (
}>
); ``` - [ ] **Step 2: Wrap ServerList in a fixed-width container (65px) and the channel sidebar in a 240px container** ```typescript return (
channel.unread)} user={user()!} selectedServer={() => params.server} onCreateOrJoinServer={() => openModal({ type: "create_or_join_server", client: client() }) } menuGenerator={props.menuGenerator} />
}>
); ``` - [ ] **Step 3: Check in dev server — server icon column should be narrow (65px), channel list should be 240px, message area fills the rest** Expected: Three visually distinct columns. The message area is clearly the widest. - [ ] **Step 4: Commit** ```bash git add packages/client/src/interface/Sidebar.tsx git commit -m "fix: explicit 65px server list and 240px channel sidebar widths" git push origin main ``` --- ## Task 5: Set up Forgejo CI — build and deploy **Files:** - Create: `.forgejo/workflows/deploy.yml` This workflow runs on every push to `main`, builds the client, and rsyncs the output to the VPS directory that Caddy serves at `mithraic.space/app`. - [ ] **Step 1: Add an SSH deploy key to Forgejo** On the VPS, generate a deploy key (if one doesn't exist): ```bash ssh-keygen -t ed25519 -C "sanctum-web-deploy" -f ~/.ssh/sanctum_web_deploy -N "" cat ~/.ssh/sanctum_web_deploy.pub >> ~/.ssh/authorized_keys cat ~/.ssh/sanctum_web_deploy # copy this — it's the private key for the secret ``` In Forgejo → `sanctum-web` repo → Settings → Secrets, add: - `DEPLOY_KEY` = the private key content from above - `DEPLOY_HOST` = your VPS IP or hostname - `DEPLOY_USER` = the SSH user on the VPS (e.g. `root` or `deploy`) - `DEPLOY_PATH` = the path Caddy serves for mithraic.space/app (e.g. `/var/www/sanctum-web`) - [ ] **Step 2: Create the workflow file** ```bash mkdir -p .forgejo/workflows ``` Create `.forgejo/workflows/deploy.yml`: ```yaml name: Build & Deploy on: push: branches: [main] jobs: deploy: runs-on: docker steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' - name: Install pnpm run: npm install -g pnpm@10 - name: Install dependencies run: pnpm install - name: Build run: pnpm --filter client build - name: Deploy to VPS env: DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} DEPLOY_USER: ${{ secrets.DEPLOY_USER }} DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} run: | mkdir -p ~/.ssh echo "$DEPLOY_KEY" > ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts rsync -avz --delete \ -e "ssh -i ~/.ssh/deploy_key" \ packages/client/dist/ \ "$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/" ``` - [ ] **Step 3: Commit and push — watch the Actions tab on Forgejo** ```bash git add .forgejo/workflows/deploy.yml git commit -m "ci: build and deploy to VPS on push to main" git push origin main ``` Expected: Forgejo Actions picks up the workflow, builds successfully, and rsyncs `dist/` to the VPS. Visit `mithraic.space/app` — the new layout should be live. --- ## Task 6: Verify the live deployment - [ ] **Step 1: Open `mithraic.space/app` in a browser** Check: - Server icon column is narrow on the left - Channel list is a fixed-width column next to it - Message area fills the remaining screen width - No horizontal overflow or clipped panels - [ ] **Step 2: Open Sanctum desktop app** Since it loads `mithraic.space/app`, it should automatically show the new layout. Verify the same proportions hold in the desktop window. - [ ] **Step 3: Test on a narrow browser window (900px wide)** Expected: The layout still shows the message area without horizontal scrollbar. If the member list appears (in a text channel), it can collapse or overlap at this width — that's acceptable for v1. - [ ] **Step 4: Tag the first release** ```bash git tag v1.0.0 git push origin v1.0.0 ```