docs: add visual reskin implementation plan
This commit is contained in:
@@ -0,0 +1,978 @@
|
|||||||
|
# Visual Reskin 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:** Reskin the app's shared visual layer (font, table/card colors, primary buttons, sidebar/toolbar, status badges, tool icons) to match the provided reference design, landing on the flagship page `request-qualification-adjustments` first.
|
||||||
|
|
||||||
|
**Architecture:** This app already has centralized theming: a large `!important`-based CSS block in `src/styles.scss` (~line 1360–1520) themes nearly every Material table/card app-wide, and `src/app/layout/components/**` is the single shared sidebar/toolbar used everywhere. Editing these few central files cascades the new look across most of the app without touching each menu individually. Only the flagship page has page-specific old-style markup (a status dot-icon and plain colored tool icons) that needs direct edits.
|
||||||
|
|
||||||
|
**Tech Stack:** Angular 17, SCSS, Angular Material, `@fontsource` (self-hosted Google Fonts npm packages).
|
||||||
|
|
||||||
|
## Global Constraints
|
||||||
|
|
||||||
|
- Every color/class change in `src/styles.scss` or the layout components is a GLOBAL change — verify it doesn't break contrast/readability anywhere it cascades to (verified in Task 6 by spot-checking a second, unrelated menu).
|
||||||
|
- No unit-test culture exists for these files (SCSS/HTML, no Karma specs) — verification is `ng build --configuration=production` succeeding plus live visual check at `http://localhost:4200` (user already has a dev server running there with `ng serve --hmr`, so SCSS edits hot-reload automatically — no rebuild/restart needed to see them).
|
||||||
|
- Colors decided in the design spec (`docs/superpowers/specs/2026-07-06-visual-reskin-design.md`), adjustable live during Task 6 if the user wants a tweak after seeing it rendered:
|
||||||
|
- Table/card header background: `#3d8b7a`, text `#ffffff`
|
||||||
|
- Primary brand color (buttons + sidebar/toolbar, replaces `#bd413a`/`#5f9adc`): `#d9652d`
|
||||||
|
- Font: IBM Plex Sans Thai (weights 100, 200, 400, 500, 700 — same set Sarabun used), self-hosted via `@fontsource/ibm-plex-sans-thai`, replacing Sarabun everywhere.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Embed IBM Plex Sans Thai font
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `rmutr-web/package.json` (add dependency)
|
||||||
|
- Modify: `rmutr-web/angular.json:41-45`
|
||||||
|
- Modify: `rmutr-web/src/index.html:10`
|
||||||
|
- Modify: `rmutr-web/src/styles.scss:133-139`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: nothing from other tasks
|
||||||
|
- Produces: global font `'IBM Plex Sans Thai'` applied via the same universal selector Sarabun used — later tasks don't depend on this directly, but it's part of the same visual pass.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Install the font package**
|
||||||
|
|
||||||
|
Run from `/Users/nut.looknut/Project/rmutr/rmutr-web`:
|
||||||
|
```bash
|
||||||
|
npm install @fontsource/ibm-plex-sans-thai
|
||||||
|
```
|
||||||
|
Expected: `package.json` gains a new dependency entry `"@fontsource/ibm-plex-sans-thai": "^5.x.x"` (exact version npm resolves to).
|
||||||
|
|
||||||
|
- [ ] **Step 2: Register the weight-specific CSS files in Angular's build**
|
||||||
|
|
||||||
|
Find, in `angular.json` (inside `projects.rmutr-web.architect.build.options`):
|
||||||
|
```json
|
||||||
|
"styles": [
|
||||||
|
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||||
|
"src/styles.scss",
|
||||||
|
"./node_modules/@syncfusion/ej2-material-theme/styles/material.css"
|
||||||
|
],
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```json
|
||||||
|
"styles": [
|
||||||
|
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||||
|
"./node_modules/@fontsource/ibm-plex-sans-thai/100.css",
|
||||||
|
"./node_modules/@fontsource/ibm-plex-sans-thai/200.css",
|
||||||
|
"./node_modules/@fontsource/ibm-plex-sans-thai/400.css",
|
||||||
|
"./node_modules/@fontsource/ibm-plex-sans-thai/500.css",
|
||||||
|
"./node_modules/@fontsource/ibm-plex-sans-thai/700.css",
|
||||||
|
"src/styles.scss",
|
||||||
|
"./node_modules/@syncfusion/ej2-material-theme/styles/material.css"
|
||||||
|
],
|
||||||
|
```
|
||||||
|
(Each of these `NNN.css` files ships full-Unicode-range `@font-face` rules — covering Thai and Latin glyphs in one font — for that one weight, and Angular CLI bundles the referenced `.woff2` files as build assets automatically.)
|
||||||
|
|
||||||
|
- [ ] **Step 3: Remove the external Google Fonts link for Sarabun**
|
||||||
|
|
||||||
|
Find, in `src/index.html`:
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Sarabun:wght@100;200;400;500;700&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
```
|
||||||
|
Change to (remove only the Sarabun line, keep Material Icons — that's a separate icon font, unrelated to this task):
|
||||||
|
```html
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Switch the global font-family**
|
||||||
|
|
||||||
|
Find, in `src/styles.scss`:
|
||||||
|
```scss
|
||||||
|
*:not(
|
||||||
|
.material-icons,
|
||||||
|
.e-btn-icon,
|
||||||
|
.e-icons
|
||||||
|
) {
|
||||||
|
font-family: 'Sarabun', sans-serif !important;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```scss
|
||||||
|
*:not(
|
||||||
|
.material-icons,
|
||||||
|
.e-btn-icon,
|
||||||
|
.e-icons
|
||||||
|
) {
|
||||||
|
font-family: 'IBM Plex Sans Thai', sans-serif !important;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Build to confirm no errors**
|
||||||
|
|
||||||
|
Run: `cd /Users/nut.looknut/Project/rmutr/rmutr-web && ng build --configuration=production`
|
||||||
|
Expected: build succeeds with no new errors (font files resolve as build assets).
|
||||||
|
|
||||||
|
- [ ] **Step 6: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add package.json package-lock.json angular.json src/index.html src/styles.scss
|
||||||
|
git commit -m "feat: embed IBM Plex Sans Thai font, replacing Sarabun CDN link"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: Global color tokens — table/card headers + primary button
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `rmutr-web/src/styles.scss:438-442` (`.bg-bpi-primary-color`)
|
||||||
|
- Modify: `rmutr-web/src/styles.scss:1379-1384` (card title bar)
|
||||||
|
- Modify: `rmutr-web/src/styles.scss:1414-1417` (`tr.mat-header-row`)
|
||||||
|
- Modify: `rmutr-web/src/styles.scss:1419-1429` (`th.mat-header-cell`)
|
||||||
|
- Modify: `rmutr-web/src/styles.scss:1484-1498` (`.tables th`)
|
||||||
|
- Modify: `rmutr-web/src/styles.scss:1530-1540` (`.table-excel th`, same pattern as `.tables`)
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: nothing from other tasks
|
||||||
|
- Produces: nothing later tasks call directly — this is a pure visual/color change other tasks don't depend on programmatically.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Change the primary action button color**
|
||||||
|
|
||||||
|
Find, in `src/styles.scss`:
|
||||||
|
```scss
|
||||||
|
.bg-bpi-primary-color {
|
||||||
|
background-color: #5f9adc !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
border: 1px solid #4a87cb !important;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```scss
|
||||||
|
.bg-bpi-primary-color {
|
||||||
|
background-color: #d9652d !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
border: 1px solid #c2551f !important;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Change the card title bar gradient**
|
||||||
|
|
||||||
|
Find, in `src/styles.scss`:
|
||||||
|
```scss
|
||||||
|
// ----- Card title bar (.mat-header-cell as wrapper div) -----
|
||||||
|
.rmutr_card > .mat-header-cell,
|
||||||
|
.rmutr_card .mat-header-cell:first-child {
|
||||||
|
background: linear-gradient(135deg, #639bd2 0%, #e6e6df 100%) !important;
|
||||||
|
padding: 10px 16px !important;
|
||||||
|
border-bottom: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rmutr_title {
|
||||||
|
color: #374151 !important;
|
||||||
|
font-size: 13px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```scss
|
||||||
|
// ----- Card title bar (.mat-header-cell as wrapper div) -----
|
||||||
|
.rmutr_card > .mat-header-cell,
|
||||||
|
.rmutr_card .mat-header-cell:first-child {
|
||||||
|
background: #3d8b7a !important;
|
||||||
|
padding: 10px 16px !important;
|
||||||
|
border-bottom: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rmutr_title {
|
||||||
|
color: #ffffff !important;
|
||||||
|
font-size: 13px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Change the Material table header background**
|
||||||
|
|
||||||
|
Find, in `src/styles.scss`:
|
||||||
|
```scss
|
||||||
|
// ----- Angular Material table header -----
|
||||||
|
tr.mat-header-row {
|
||||||
|
height: 40px !important;
|
||||||
|
background: #e6e6df !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
th.mat-header-cell {
|
||||||
|
color: #374151 !important;
|
||||||
|
background: transparent !important;
|
||||||
|
font-size: 11.5px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
letter-spacing: 0.3px !important;
|
||||||
|
white-space: nowrap;
|
||||||
|
border-color: #e5e7eb !important;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 0 10px !important;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```scss
|
||||||
|
// ----- Angular Material table header -----
|
||||||
|
tr.mat-header-row {
|
||||||
|
height: 40px !important;
|
||||||
|
background: #3d8b7a !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
th.mat-header-cell {
|
||||||
|
color: #ffffff !important;
|
||||||
|
background: transparent !important;
|
||||||
|
font-size: 11.5px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
letter-spacing: 0.3px !important;
|
||||||
|
white-space: nowrap;
|
||||||
|
border-color: #2f6d5f !important;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 0 10px !important;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Change the plain `.tables` header background**
|
||||||
|
|
||||||
|
Find, in `src/styles.scss` (inside the `.tables { ... }` block):
|
||||||
|
```scss
|
||||||
|
th:not(.th_class) {
|
||||||
|
background: #e6e6df !important;
|
||||||
|
color: #374151 !important;
|
||||||
|
border-bottom: 1px solid #d1d5db !important;
|
||||||
|
border-right: 1px solid #e5e7eb !important;
|
||||||
|
font-size: 11.5px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
letter-spacing: 0.3px !important;
|
||||||
|
text-transform: uppercase;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 7px 10px !important;
|
||||||
|
|
||||||
|
&:first-child { border-radius: 10px 0 0 0 !important; }
|
||||||
|
&:last-child { border-radius: 0 10px 0 0 !important; border-right: none !important; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change the `background`/`color`/`border-bottom` lines to:
|
||||||
|
```scss
|
||||||
|
th:not(.th_class) {
|
||||||
|
background: #3d8b7a !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
border-bottom: 1px solid #2f6d5f !important;
|
||||||
|
border-right: 1px solid #2f6d5f !important;
|
||||||
|
font-size: 11.5px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
letter-spacing: 0.3px !important;
|
||||||
|
text-transform: uppercase;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 7px 10px !important;
|
||||||
|
|
||||||
|
&:first-child { border-radius: 10px 0 0 0 !important; }
|
||||||
|
&:last-child { border-radius: 0 10px 0 0 !important; border-right: none !important; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Apply the identical change to `.table-excel`**
|
||||||
|
|
||||||
|
Find, in `src/styles.scss` (inside the `.table-excel { ... }` block, directly below `.tables`):
|
||||||
|
```scss
|
||||||
|
th:not(.th_class) {
|
||||||
|
background: #e6e6df !important;
|
||||||
|
color: #374151 !important;
|
||||||
|
border-bottom: 1px solid #d1d5db !important;
|
||||||
|
border-right: 1px solid #e5e7eb !important;
|
||||||
|
font-size: 11.5px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
letter-spacing: 0.3px !important;
|
||||||
|
text-transform: uppercase;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 7px 10px !important;
|
||||||
|
|
||||||
|
&:first-child { border-radius: 10px 0 0 0 !important; }
|
||||||
|
&:last-child { border-radius: 0 10px 0 0 !important; border-right: none !important; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```scss
|
||||||
|
th:not(.th_class) {
|
||||||
|
background: #3d8b7a !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
border-bottom: 1px solid #2f6d5f !important;
|
||||||
|
border-right: 1px solid #2f6d5f !important;
|
||||||
|
font-size: 11.5px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
letter-spacing: 0.3px !important;
|
||||||
|
text-transform: uppercase;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 7px 10px !important;
|
||||||
|
|
||||||
|
&:first-child { border-radius: 10px 0 0 0 !important; }
|
||||||
|
&:last-child { border-radius: 0 10px 0 0 !important; border-right: none !important; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 6: Build to confirm no errors**
|
||||||
|
|
||||||
|
Run: `cd /Users/nut.looknut/Project/rmutr/rmutr-web && ng build --configuration=production`
|
||||||
|
Expected: build succeeds with no new errors.
|
||||||
|
|
||||||
|
- [ ] **Step 7: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src/styles.scss
|
||||||
|
git commit -m "feat: recolor global table headers to teal and primary button to orange"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 3: Global badge + icon-btn utility classes
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `rmutr-web/src/styles.scss` (add new global classes)
|
||||||
|
- Modify: `rmutr-web/src/app/feature/budget-request/request/request-budget-statistics/presenter/list/request-budget-statistics-list/list-between-year/list-between-year.component.scss:183-215`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: nothing from other tasks
|
||||||
|
- Produces: global classes `.badge`, `.badge-success`, `.badge-warning`, `.badge-pending`, `.badge-draft`, `.icon-btn`, `.icon-btn--view`, `.icon-btn--edit`, `.icon-btn--delete` — Task 5 uses these exact class names on the flagship page.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Add the global badge classes to styles.scss**
|
||||||
|
|
||||||
|
Add this new block at the end of `src/styles.scss` (append, don't replace anything):
|
||||||
|
```scss
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Shared status badges (pill-shaped)
|
||||||
|
// ----------------------------------------
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 20px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-success {
|
||||||
|
background: #d1fae5;
|
||||||
|
color: #065f46;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-warning {
|
||||||
|
background: #fef3c7;
|
||||||
|
color: #92400e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-pending {
|
||||||
|
background: #dbeafe;
|
||||||
|
color: #1e40af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-draft {
|
||||||
|
background: #f3f4f6;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Shared table tool icon buttons (soft circular background)
|
||||||
|
// ----------------------------------------
|
||||||
|
.icon-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 0 2px;
|
||||||
|
transition: opacity 0.15s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-icons {
|
||||||
|
font-size: 16px !important;
|
||||||
|
width: 16px !important;
|
||||||
|
height: 16px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-btn--view {
|
||||||
|
background: #dbeafe;
|
||||||
|
color: #007aff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-btn--edit {
|
||||||
|
background: #fef3c7;
|
||||||
|
color: #f8a300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-btn--delete {
|
||||||
|
background: #fee2e2;
|
||||||
|
color: #dc2626;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Remove the now-duplicated badge definitions from list-between-year.component.scss**
|
||||||
|
|
||||||
|
Find, in `list-between-year.component.scss`:
|
||||||
|
```scss
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 20px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-between {
|
||||||
|
background: #ede9fe;
|
||||||
|
color: #5b21b6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-success {
|
||||||
|
background: #d1fae5;
|
||||||
|
color: #065f46;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-warning {
|
||||||
|
background: #fef3c7;
|
||||||
|
color: #92400e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-pending {
|
||||||
|
background: #dbeafe;
|
||||||
|
color: #1e40af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-draft {
|
||||||
|
background: #f3f4f6;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to (keep only `.badge-between`, which is specific to this component's "request type" pill and has no global equivalent — `.badge` and the 4 status-color variants now come from the global stylesheet added in Step 1):
|
||||||
|
```scss
|
||||||
|
.badge-between {
|
||||||
|
background: #ede9fe;
|
||||||
|
color: #5b21b6;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Build to confirm no errors and no visual regression on the between-year list**
|
||||||
|
|
||||||
|
Run: `cd /Users/nut.looknut/Project/rmutr/rmutr-web && ng build --configuration=production`
|
||||||
|
Expected: build succeeds with no new errors. The between-year list's badges (`ร่าง`/`ส่งงานแผน`/`ส่งแก้ไข`/`ตรวจสอบแล้ว`) must still render identically since the global classes are byte-identical to what was removed.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src/styles.scss "src/app/feature/budget-request/request/request-budget-statistics/presenter/list/request-budget-statistics-list/list-between-year/list-between-year.component.scss"
|
||||||
|
git commit -m "feat: promote badge pill styles to global, add shared icon-btn utility"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 4: Sidebar/toolbar color swap
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `rmutr-web/src/app/layout/components/menu-bar/menu-bar.component.scss`
|
||||||
|
- Modify: `rmutr-web/src/app/layout/components/menu/collapsable/collapsable.component.scss`
|
||||||
|
- Modify: `rmutr-web/src/app/layout/components/menu/basic-menu/basic-menu.component.scss`
|
||||||
|
- Modify: `rmutr-web/src/app/layout/components/tool-bar/tool-bar.component.scss`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: nothing from other tasks
|
||||||
|
- Produces: nothing later tasks depend on — sidebar/toolbar are always-rendered shell components, no wiring needed.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Recolor `menu-bar.component.scss`**
|
||||||
|
|
||||||
|
Find:
|
||||||
|
```scss
|
||||||
|
.sidebar-icon-wrap {
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 11px;
|
||||||
|
background: #bd413a;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
box-shadow: 0 2px 8px rgba(189, 65, 58, 0.3);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```scss
|
||||||
|
.sidebar-icon-wrap {
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 11px;
|
||||||
|
background: #d9652d;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
box-shadow: 0 2px 8px rgba(217, 101, 45, 0.3);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Find:
|
||||||
|
```scss
|
||||||
|
.sidebar-subtitle {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #bd413a;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```scss
|
||||||
|
.sidebar-subtitle {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #d9652d;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Recolor `collapsable.component.scss`**
|
||||||
|
|
||||||
|
Find:
|
||||||
|
```scss
|
||||||
|
.bgMenu {
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: background-color 0.15s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #fef2f2;
|
||||||
|
|
||||||
|
.se_item {
|
||||||
|
color: #bd413a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
color: #bd413a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.se_icon {
|
||||||
|
color: #bd413a !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgActive {
|
||||||
|
background-color: #fef2f2;
|
||||||
|
border-left: 3px solid #bd413a;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.se_item {
|
||||||
|
color: #bd413a;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
color: #bd413a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.se_icon {
|
||||||
|
color: #bd413a !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```scss
|
||||||
|
.bgMenu {
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: background-color 0.15s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #fdf0e8;
|
||||||
|
|
||||||
|
.se_item {
|
||||||
|
color: #d9652d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
color: #d9652d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.se_icon {
|
||||||
|
color: #d9652d !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgActive {
|
||||||
|
background-color: #fdf0e8;
|
||||||
|
border-left: 3px solid #d9652d;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.se_item {
|
||||||
|
color: #d9652d;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
color: #d9652d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.se_icon {
|
||||||
|
color: #d9652d !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Find, in the `.se_item_children` block near the end of the same file:
|
||||||
|
```scss
|
||||||
|
::ng-deep .se_item_active {
|
||||||
|
border-left: 2px solid #bd413a !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
|
||||||
|
.se_item {
|
||||||
|
color: #bd413a !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
color: #bd413a !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .bgMenu:hover {
|
||||||
|
.se_item { color: #bd413a !important; }
|
||||||
|
.menu-icon { color: #bd413a !important; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```scss
|
||||||
|
::ng-deep .se_item_active {
|
||||||
|
border-left: 2px solid #d9652d !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
|
||||||
|
.se_item {
|
||||||
|
color: #d9652d !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
color: #d9652d !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .bgMenu:hover {
|
||||||
|
.se_item { color: #d9652d !important; }
|
||||||
|
.menu-icon { color: #d9652d !important; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Recolor `basic-menu.component.scss`**
|
||||||
|
|
||||||
|
Find:
|
||||||
|
```scss
|
||||||
|
.se_item_warpper {
|
||||||
|
margin: 1px 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: background-color 0.15s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #fef2f2;
|
||||||
|
|
||||||
|
.se_item {
|
||||||
|
color: #bd413a !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
color: #bd413a !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```scss
|
||||||
|
.se_item_warpper {
|
||||||
|
margin: 1px 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: background-color 0.15s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #fdf0e8;
|
||||||
|
|
||||||
|
.se_item {
|
||||||
|
color: #d9652d !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
color: #d9652d !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Find:
|
||||||
|
```scss
|
||||||
|
.menu-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #bd413a;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 0 6px;
|
||||||
|
line-height: 1;
|
||||||
|
margin-left: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.se_item_active {
|
||||||
|
background-color: #fef2f2 !important;
|
||||||
|
border-left: 3px solid #bd413a;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.se_item {
|
||||||
|
color: #bd413a !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
color: #bd413a !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```scss
|
||||||
|
.menu-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #d9652d;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 0 6px;
|
||||||
|
line-height: 1;
|
||||||
|
margin-left: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.se_item_active {
|
||||||
|
background-color: #fdf0e8 !important;
|
||||||
|
border-left: 3px solid #d9652d;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.se_item {
|
||||||
|
color: #d9652d !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon {
|
||||||
|
color: #d9652d !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Recolor `tool-bar.component.scss`**
|
||||||
|
|
||||||
|
Find:
|
||||||
|
```scss
|
||||||
|
.user-avatar-circle {
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #bd413a;
|
||||||
|
color: #ffffff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```scss
|
||||||
|
.user-avatar-circle {
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #d9652d;
|
||||||
|
color: #ffffff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Find:
|
||||||
|
```scss
|
||||||
|
.logout-btn {
|
||||||
|
color: #bd413a;
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #fef2f2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```scss
|
||||||
|
.logout-btn {
|
||||||
|
color: #d9652d;
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #fdf0e8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Build to confirm no errors**
|
||||||
|
|
||||||
|
Run: `cd /Users/nut.looknut/Project/rmutr/rmutr-web && ng build --configuration=production`
|
||||||
|
Expected: build succeeds with no new errors.
|
||||||
|
|
||||||
|
- [ ] **Step 6: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add src/app/layout/components/menu-bar/menu-bar.component.scss src/app/layout/components/menu/collapsable/collapsable.component.scss src/app/layout/components/menu/basic-menu/basic-menu.component.scss src/app/layout/components/tool-bar/tool-bar.component.scss
|
||||||
|
git commit -m "feat: recolor sidebar and toolbar brand color from red to orange"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 5: Apply badge + icon-btn to the flagship page
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `rmutr-web/src/app/feature/budget-request/request-qualification-adjustments/presenter/list/request-qualification-adjustments-list/request-qualification-adjustments-list.component.html`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `.badge`/`.badge-success` and `.icon-btn`/`.icon-btn--view`/`.icon-btn--edit`/`.icon-btn--delete` from Task 3
|
||||||
|
- Produces: nothing later tasks depend on — this is the last page-specific edit in this plan.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Replace the status dot-icon with a badge pill**
|
||||||
|
|
||||||
|
Find, in `request-qualification-adjustments-list.component.html`:
|
||||||
|
```html
|
||||||
|
<ng-container matColumnDef="status_id">
|
||||||
|
<th mat-header-cell *matHeaderCellDef > สถานะ </th>
|
||||||
|
<td mat-cell *matCellDef="let x" style="text-align: center;">
|
||||||
|
<span class="material-icons" [ngStyle]="{ 'color' : (x.status_id == 1) ? '#06B958' : 'rgba(0, 0, 0, 0.54)' }">
|
||||||
|
fiber_manual_record
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```html
|
||||||
|
<ng-container matColumnDef="status_id">
|
||||||
|
<th mat-header-cell *matHeaderCellDef > สถานะ </th>
|
||||||
|
<td mat-cell *matCellDef="let x" style="text-align: center;">
|
||||||
|
<span class="badge" [ngClass]="(x.status_id == 1) ? 'badge-success' : 'badge-draft'">
|
||||||
|
{{ (x.status_id == 1) ? 'ปกติ' : 'ไม่ใช้งาน' }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Replace the plain tool icons with icon-btn circles**
|
||||||
|
|
||||||
|
Find, in the same file:
|
||||||
|
```html
|
||||||
|
<ng-container matColumnDef="action">
|
||||||
|
<th mat-header-cell *matHeaderCellDef > เครื่องมือ </th>
|
||||||
|
<td mat-cell *matCellDef="let x" style="text-align: center;">
|
||||||
|
<span class="material-icons" style="cursor: pointer;color: #007AFF;" (click)="word(x.budget_income_qualification_uid,'pdf')">description</span>
|
||||||
|
|
||||||
|
<span class="material-icons" style="cursor: pointer;color: #F8A300;" (click)="edit(x.budget_income_qualification_uid)">create</span>
|
||||||
|
|
||||||
|
<span class="material-icons" style="cursor: pointer;color: #BD413A;" (click)="onDelete(x)">
|
||||||
|
delete_forever
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
```
|
||||||
|
Change to:
|
||||||
|
```html
|
||||||
|
<ng-container matColumnDef="action">
|
||||||
|
<th mat-header-cell *matHeaderCellDef > เครื่องมือ </th>
|
||||||
|
<td mat-cell *matCellDef="let x" style="text-align: center;">
|
||||||
|
<span class="icon-btn icon-btn--view" (click)="word(x.budget_income_qualification_uid,'pdf')">
|
||||||
|
<span class="material-icons">description</span>
|
||||||
|
</span>
|
||||||
|
<span class="icon-btn icon-btn--edit" (click)="edit(x.budget_income_qualification_uid)">
|
||||||
|
<span class="material-icons">create</span>
|
||||||
|
</span>
|
||||||
|
<span class="icon-btn icon-btn--delete" (click)="onDelete(x)">
|
||||||
|
<span class="material-icons">delete_forever</span>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Build to confirm no errors**
|
||||||
|
|
||||||
|
Run: `cd /Users/nut.looknut/Project/rmutr/rmutr-web && ng build --configuration=production`
|
||||||
|
Expected: build succeeds with no new errors.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add "src/app/feature/budget-request/request-qualification-adjustments/presenter/list/request-qualification-adjustments-list/request-qualification-adjustments-list.component.html"
|
||||||
|
git commit -m "feat: apply badge pill and icon-btn styles to qualification-adjustments list"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 6: End-to-end manual verification
|
||||||
|
|
||||||
|
**Files:** none (verification only)
|
||||||
|
|
||||||
|
**Interfaces:** none
|
||||||
|
|
||||||
|
- [ ] **Step 1: Confirm the dev server is live**
|
||||||
|
|
||||||
|
The user already has `ng serve --hmr` running at `http://localhost:4200` — all 5 prior tasks' SCSS/HTML changes hot-reload into that session automatically. No restart needed.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Check the flagship page**
|
||||||
|
|
||||||
|
Open `http://localhost:4200/app/request-qualification-adjustments`.
|
||||||
|
Expected: search card header and table header are teal (`#3d8b7a`) with white text; "ยื่นคำขอ" button is orange (`#d9652d`); status column shows a green "ปกติ" pill (or gray "ไม่ใช้งาน") instead of a dot; the 3 tool icons (view/edit/delete) render as soft-colored circles instead of bare icons; font renders as IBM Plex Sans Thai (check via browser devtools computed `font-family` on any text element — should read `"IBM Plex Sans Thai", sans-serif`).
|
||||||
|
|
||||||
|
- [ ] **Step 3: Check the sidebar and toolbar**
|
||||||
|
|
||||||
|
On any page, confirm: sidebar logo block, active-menu-item highlight/left-border, and the top-right user avatar circle + logout icon are all orange (`#d9652d`) instead of red (`#bd413a`).
|
||||||
|
|
||||||
|
- [ ] **Step 4: Regression check — between-year list badges**
|
||||||
|
|
||||||
|
Open the "คำขอระหว่างปี" menu (built in an earlier feature). Confirm the "ร่าง"/"ส่งงานแผน"/"ส่งแก้ไข"/"ตรวจสอบแล้ว" badges still render with their original colors (gray/blue/amber/green) — this confirms Task 3's dedup didn't break the existing page.
|
||||||
|
|
||||||
|
- [ ] **Step 5: Regression check — one unrelated menu**
|
||||||
|
|
||||||
|
Open any other menu with a data table (e.g. "ต้นฉบับเสนอโครงการ ง.5"). Confirm its table header is now teal (cascaded automatically from Task 2's global change) and nothing else looks visually broken (no missing borders, no unreadable text contrast).
|
||||||
|
|
||||||
|
- [ ] **Step 6: Report back to the user**
|
||||||
|
|
||||||
|
Summarize what was changed and ask if any color/spacing needs adjusting before considering this phase done. Remaining menus' badge/icon-btn adoption (beyond what already cascades from the global table/button/sidebar colors) is explicitly out of scope for this plan — a follow-up phase per the design spec.
|
||||||
Reference in New Issue
Block a user