diff --git a/CLAUDE.md b/CLAUDE.md index d134955..f089223 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -15,8 +15,7 @@ Installed into `frappe-bench` as a normal app. Python code is at `jey_theme/` (F Run from `frappe-bench/` (the bench root), not this app dir. -- `bench build --app jey_theme` — rebuild JS bundle after editing `jey_theme/public/js/jey_theme.js`. -- CSS-only changes: no build needed, just hard-reload the browser. +- `bench build --app jey_theme` — required after **CSS** edits (`jey_theme.bundle.css` → hashed file in `public/dist/css/`). JS is served raw and needs only a hard reload. - `bench migrate` — runs the `after_migrate` hook that rebuilds the Taxes Az workspace from `setup/taxes_workspace.py`. - `bench execute jey_theme.setup.taxes_workspace.setup` — re-run the workspace setup without a full migrate. - `bench restart` — reload Python workers after editing `access_control.py` or `hooks.py`. @@ -128,12 +127,44 @@ Idempotent setup run via `after_migrate`. ### Frontend: multi-theme system -Bundle entry: `jey_theme/public/js/jey_theme.js`. CSS: `jey_theme/public/css/{shared,theme_chrome,theme_modern}.css`. All four are loaded via `app_include_css` / `app_include_js` in `hooks.py` for both desk and web contexts. +JS entry: `jey_theme/public/js/jey_theme.js` (served raw via `app_include_js`, not bundled). +CSS: **one file**, `jey_theme/public/css/jey_theme.bundle.css` — the former +`shared.css` / `theme_chrome.css` / `theme_modern.css` were concatenated into it +(in that order, still marked by `/* ===== .css ===== */` banners) so the +desk's preload header stays under the edge proxy's 4 KB buffer. Edit the bundle +directly; there are no separate source files to regenerate it from. +- **CSS changes need `bench build --app jey_theme`.** `app_include_css` names the + bundle, and esbuild emits the hashed `public/dist/css/jey_theme.bundle..css` + that `sites/assets/assets.json` actually points the browser at. Editing the bundle + alone changes nothing in the browser. +- JS changes need only a hard reload — but `/assets/jey_theme/js/jey_theme.js` is a + hashless path under a 1-year nginx cache, so it really does have to be a *hard* + reload (or a cache-disabled session). - Theme selector lives in `data-jey-theme` on ``, stored in `localStorage("jey-theme")`. Default: `chrome`. Set before first paint by an IIFE at the top of `jey_theme.js`. -- Themes supported: **chrome** (metallic rings), **silk** (warm ivory & champagne-gold, frosted cards). No dark/light variants — each theme is self-contained. +- Themes supported: **chrome** (metallic rings), **silk** (warm ivory & champagne-gold + glass-neumorphism, ported from `public/silk_dashboard_crisp.html` — that mockup is + silk's design reference; keep the two in sync). + No dark/light variants — each theme is self-contained. - Theme-specific CSS MUST be wrapped in `[data-jey-theme="themename"]`. Keyframes MUST be prefixed `jey--*` to avoid cross-theme name collisions. -- Shared CSS (checkboxes, icon base sizing, switcher UI, column-resize rules) lives in `shared.css` without theme selectors. +- Shared CSS (checkboxes, icon base sizing, switcher UI, column-resize rules, the + card icon-tile defaults) lives in the `shared.css` section without theme selectors. + +**Frosted glass (silk, and any future glass theme) — two rules that cost real +debugging time:** +- **One `backdrop-filter` per stack.** A frosted element inside another frosted + element paints as an opaque white block on real GPUs; headless Chrome + (SwiftShader) renders it correctly, so it passes every test render. Only the + outermost surface gets the filter — currently `.widget`, `.form-page`, + `.frappe-list .result-container`, `.navbar-search-bar`, `.dropdown-navbar-user`, + `.desktop-navbar-modal-search`, `.jey-chrome`. Everything nested (icon tiles, + chips, count pills, buttons) gets a translucent fill and no filter. There's a + backstop rule near the Modals section, but don't rely on it — check with the + live-DOM audit (walk every element, flag any whose ancestor also has a + non-`none` computed `backdropFilter`). +- **On silk it's the translucency, not the blur, that reads as glass.** The fabric + is near-uniform, so a strong blur averages it into a flat opaque panel. Light + blur (6px) over a very translucent warm fill is what lets it show through. ### Frontend: per-theme icons @@ -153,11 +184,10 @@ Keep this IIFE minimal and synchronous — anything slow here delays first paint ## Adding a new theme -1. Create `jey_theme/public/css/theme_mytheme.css` with `[data-jey-theme="mytheme"]` selectors. Prefix keyframes `jey-mytheme-*`. +1. Append a `/* ===== theme_mytheme.css ===== */` section to `jey_theme/public/css/jey_theme.bundle.css`, with every rule wrapped in `[data-jey-theme="mytheme"]`. Prefix keyframes `jey-mytheme-*`. Do NOT add a new file/`app_include_css` entry — extra preload-header lines are what the single bundle exists to avoid. 2. Add `THEME_ICONS.mytheme = { ... }` in `jey_theme.js` (only override keys you care about). -3. Add an entry to `JEY_THEMES` array in the switcher section of `jey_theme.js`. -4. Add the CSS file to both `app_include_css` and `web_include_css` in `hooks.py`. -5. `bench build --app jey_theme`. +3. Add an entry to the `JEY_THEMES` array in the switcher section of `jey_theme.js`, and a `.jey-theme-preview--mytheme` swatch in the bundle's shared section. +4. `bench build --app jey_theme`. ## Rules diff --git a/jey_theme/config/desk_layout.json b/jey_theme/config/desk_layout.json index a00c3a6..840e82a 100644 --- a/jey_theme/config/desk_layout.json +++ b/jey_theme/config/desk_layout.json @@ -1,4 +1,324 @@ { + "blocked_doctypes": [ + "Server Script", + "Client Script", + "Website Script", + "Subcontracting Inward Order Secondary Item", + "Subcontracting Inward Order Service Item", + "Subcontracting Inward Order Received Item", + "Subcontracting Inward Order Item", + "Subcontracting Inward Order", + "Subcontracting BOM", + "Subcontracting Receipt", + "Subcontracting Receipt Supplied Item", + "Subcontracting Receipt Item", + "Subcontracting Order", + "Subcontracting Order Supplied Item", + "Subcontracting Order Item", + "Subcontracting Order Service Item", + "Job Opening" + ], "version": 1, - "workspaces": {} + "workspaces": { + "Assets": { + "cards": { + "Maintenance": { + "state": "hidden" + } + }, + "links": { + "DocType::Asset Capitalization": { + "state": "blocked" + }, + "DocType::Asset Maintenance": { + "state": "blocked" + }, + "DocType::Asset Maintenance Log": { + "state": "blocked" + }, + "DocType::Asset Maintenance Team": { + "state": "blocked" + }, + "DocType::Asset Repair": { + "state": "blocked" + }, + "DocType::Asset Value Adjustment": { + "state": "blocked" + } + }, + "state": "visible" + }, + "Buying": { + "cards": { + "Supplier Scorecard": { + "state": "hidden" + } + }, + "links": { + "DocType::Promotional Scheme": { + "state": "blocked" + }, + "DocType::Request for Quotation": { + "state": "blocked" + }, + "DocType::Supplier Quotation": { + "state": "blocked" + }, + "DocType::Supplier Scorecard": { + "state": "blocked" + }, + "DocType::Supplier Scorecard Criteria": { + "state": "blocked" + }, + "DocType::Supplier Scorecard Standing": { + "state": "blocked" + }, + "DocType::Supplier Scorecard Variable": { + "state": "blocked" + }, + "Report::Subcontracted Item To Be Received": { + "state": "blocked" + }, + "Report::Subcontracted Raw Materials To Be Transferred": { + "state": "blocked" + }, + "Report::Supplier Quotation Comparison": { + "state": "blocked" + } + }, + "state": "visible" + }, + "Expenses": { + "cards": { + "Fleet Management": { + "state": "hidden" + }, + "Travel": { + "state": "hidden" + } + }, + "state": "visible" + }, + "Invoicing": { + "cards": { + "Share Management": { + "state": "hidden" + } + }, + "links": { + "DocType::Share Transfer": { + "state": "blocked" + }, + "DocType::Shareholder": { + "state": "blocked" + }, + "DocType::Tax Rule": { + "state": "blocked" + }, + "DocType::Tax Withholding Category": { + "state": "blocked" + }, + "Report::Share Balance": { + "state": "blocked" + }, + "Report::Share Ledger": { + "state": "blocked" + } + }, + "state": "visible" + }, + "Manufacturing": { + "cards": { + "Subcontracting": { + "state": "hidden" + } + }, + "links": { + "DocType::Downtime Entry": { + "state": "blocked" + }, + "DocType::Item Lead Time": { + "state": "blocked" + }, + "DocType::Production Plan": { + "state": "blocked" + }, + "DocType::Sales Forecast": { + "state": "blocked" + }, + "DocType::Subcontracting BOM": { + "state": "blocked" + }, + "DocType::Subcontracting Order": { + "state": "blocked" + }, + "DocType::Subcontracting Receipt": { + "state": "blocked" + }, + "Report::Downtime Analysis": { + "state": "blocked" + }, + "Report::Production Planning Report": { + "state": "blocked" + }, + "Report::Quality Inspection Summary": { + "state": "blocked" + }, + "Report::Subcontract Order Summary": { + "state": "blocked" + }, + "Report::Subcontracted Item To Be Received": { + "state": "blocked" + }, + "Report::Subcontracted Raw Materials To Be Transferred": { + "state": "blocked" + } + }, + "state": "visible" + }, + "Payroll": { + "links": { + "DocType::Income Tax Slab": { + "state": "blocked" + }, + "Report::Income Tax Computation": { + "state": "blocked" + }, + "Report::Salary Payments via ECS": { + "state": "blocked" + } + }, + "state": "visible" + }, + "Recruitment": { + "cards": { + "Appointment": { + "state": "hidden" + }, + "Interviews": { + "state": "hidden" + }, + "Reports": { + "state": "hidden" + } + }, + "links": { + "DocType::Appointment Letter": { + "state": "blocked" + }, + "DocType::Appointment Letter Template": { + "state": "blocked" + }, + "DocType::Employee Referral": { + "state": "blocked" + }, + "DocType::Interview": { + "state": "blocked" + }, + "DocType::Interview Feedback": { + "state": "blocked" + }, + "DocType::Interview Type": { + "state": "blocked" + }, + "DocType::Job Requisition": { + "state": "blocked" + }, + "DocType::Staffing Plan": { + "state": "blocked" + }, + "Report::Recruitment Analytics": { + "state": "blocked" + } + }, + "state": "visible" + }, + "Selling": { + "links": { + "DocType::Coupon Code": { + "state": "blocked" + } + }, + "state": "visible" + }, + "Stock": { + "added": { + "DocType::Landed Cost Voucher": { + "card": "Stock Transactions", + "label": "Landed Cost Voucher", + "link_to": "Landed Cost Voucher", + "link_type": "DocType" + } + }, + "cards": { + "Serial No and Batch": { + "state": "hidden" + }, + "Tools": { + "state": "hidden" + } + }, + "links": { + "DocType::Batch": { + "state": "blocked" + }, + "DocType::Installation Note": { + "state": "blocked" + }, + "DocType::Material Request": { + "state": "blocked" + }, + "DocType::Packing Slip": { + "state": "blocked" + }, + "DocType::Quality Inspection": { + "state": "blocked" + }, + "DocType::Quality Inspection Template": { + "state": "blocked" + }, + "DocType::Quick Stock Balance": { + "state": "blocked" + }, + "DocType::Serial No": { + "state": "blocked" + }, + "DocType::Stock Reconciliation": { + "state": "blocked" + }, + "Report::Serial No Ledger": { + "state": "blocked" + }, + "Report::Serial No Service Contract Expiry": { + "state": "blocked" + }, + "Report::Serial No Status": { + "state": "blocked" + }, + "Report::Serial No Warranty Expiry": { + "state": "blocked" + }, + "Report::Serial No and Batch Traceability": { + "state": "blocked" + }, + "Report::Subcontracted Item To Be Received": { + "state": "blocked" + }, + "Report::Subcontracted Raw Materials To Be Transferred": { + "state": "blocked" + } + }, + "order": { + "Tools": [ + "DocType::Landed Cost Voucher", + "DocType::Stock Reconciliation", + "DocType::Packing Slip", + "DocType::Quality Inspection", + "DocType::Quality Inspection Template", + "DocType::Quick Stock Balance" + ] + }, + "state": "visible" + } + } } diff --git a/jey_theme/public/images/silk-bg.jpg b/jey_theme/public/images/silk-bg.jpg new file mode 100644 index 0000000..0303d7a Binary files /dev/null and b/jey_theme/public/images/silk-bg.jpg differ