# DESIGN.md — Style & UI Convention (AutoShopee Kit)

> Quy ước thiết kế / CSS dùng chung cho extension AutoShopee Kit.
> Mọi UI mới **bắt buộc** tuân theo file này để giữ giao diện nhất quán.
> Reference design chuẩn nhất hiện tại: cụm **Shopee Video** (`src/app/vue/views/Shopee/Video/*`, `src/app/vue/components/Shopee/Video/*`).

---

## 1. Stack & nơi đặt style

| Hạng mục | Quy ước |
|---|---|
| UI framework | **View Design (iView for Vue 2)** — `view-design@4.7.0`. Dùng component có sẵn (`Button`, `Modal`, `Input`, `Poptip`, `RadioGroup`, `Spin`, `Icon`…). |
| Vue | **Vue 2 Options API** (KHÔNG Composition API). |
| CSS engine | **SCSS** (`<style lang="scss" scoped>`) cho component + **Tailwind** (utility cơ bản) + một ít global trong `app.css`. |
| Icon | `Icon` của iView (`ios-*`, `md-*`) là chính; FontAwesome (`font-awesome.min.css`) cho trường hợp đặc biệt. |
| Import global | Tập trung ở `src/app/vue/plugins/loader.js`: `font-awesome.min.css` → `view-design/.../iview.css` → `@/vue/styles/iview-override.scss` → `@/vue/styles/app.css`. Content script tự inject `iview.css` qua CDN (`content/service.js`). |

**Quy tắc vàng:** style riêng của component đặt **trong SFC** dưới `<style lang="scss" scoped>`. KHÔNG thêm class vào `app.css` trừ khi thật sự là utility/override toàn cục dùng nhiều nơi.

### 1.1 Design token — `src/app/vue/styles/tokens.scss`

Mọi SFC BẮT BUỘC mở đầu block style bằng:

```scss
<style lang="scss" scoped>
@import '@/vue/styles/tokens.scss';
```

File này khai báo toàn bộ biến ở mục 3–4 dưới dạng SCSS variable (`$c-brand`, `$c-text-strong`,
`$radius-card`, `$shadow-card`, `$motion-fast`…) **KHÔNG hardcode hex trong SFC nữa**.

Mixin dùng chung:

| Mixin | Tác dụng |
|---|---|
| `@include card($padding)` | nền trắng + radius 12px + `$shadow-card` + padding |
| `@include card-hover` | nâng shadow + `translateY(-1px)` khi hover |
| `@include ellipsis` | 1 dòng, cắt `…`, kèm `min-width: 0` |
| `@include line-clamp($n)` | cắt nhiều dòng |
| `@include scrollbar($size)` | scrollbar mảnh theo palette |
| `@include transition-soft(...)` | transition liệt kê property |

### 1.2 Override iView toàn cục — `src/app/vue/styles/iview-override.scss`

Skin brand Shopee cho Button / Input / Select / Modal / Card / Table / Tabs / Page /
Radio / Checkbox / Switch / Spin / Progress / Message / Poptip. Import **sau** `iview.css`
nên luôn thắng cascade mà không cần `!important`.

Khi làm UI mới: KHÔNG lặp lại các override đã có ở file này trong SFC; chỉ override cục bộ
phần thật sự đặc thù của component, bằng cách nối class `.ivu-*`.

### 1.3 Prefix BEM theo feature

| Prefix | Phạm vi |
|---|---|
| `sv-` | Shopee Video |
| `sp-` | Shopee Spy |
| `fs-` | Shopee FlashSale |
| `ad-` | Shopee Ads |
| `kw-` | Shopee Keyword |
| `au-` | Shopee Auto (Dashboard, RatingOrder, ReplyRating, PushProduct) |
| `sm-` | Send Message |
| `pt-` | Printer / PdfLog |
| `st-` | Setting |
| `lg-` | Login / Register |
| `tk-` | TikTok |
| `wg-` | Widget |
| `pl-` | Plugin |
| `pu-` | Popup / LayoutPopup |

---

## 2. Đặt tên class — BEM + prefix theo feature

Theo đúng pattern cụm Video (`sv-` = Shopee Video):

```
.sv-dash               // block
.sv-dash__toolbar      // block__element
.sv-card--id           // block--modifier (ít dùng, ưu tiên is-*)
.sv-card.is-done       // state qua class `is-*`
```

Quy tắc:
- **1 prefix ngắn / feature** (`sv-` cho Shopee Video). Feature mới → chọn prefix riêng, viết thường, kebab-case.
- **`__element`** cho phần tử con, **`--modifier`** cho biến thể tĩnh.
- **`is-*`** cho trạng thái động: `is-active`, `is-done`, `is-error`, `is-pending`, `is-archived`, `is-sold`, `is-shopee`, `is-tiktok`, `is-product`.
- Trong SCSS lồng bằng `&`:

```scss
.sv-card {
  &__body { ... }
  &.is-done::before { background: #19be6b; }
  &:hover &__actions { opacity: 1; }
}
```

- Override component iView: nối suffix `.ivu-*` để tăng đặc thù, không dùng `!important` (vd `&__post.ivu-btn { ... }`).

---

## 3. Color tokens

Palette chuẩn = **iView + brand Shopee**. Dùng đúng các giá trị dưới đây (KHÔNG tự bịa hex mới).

### Brand & accent
| Token | Hex | Dùng cho |
|---|---|---|
| Shopee primary | `#ee4d2d` | nút post/CTA chính, giá tiền, accent brand |
| Shopee hover | `#f05f43` / `#f5613e` | hover của nút Shopee |
| Shopee tint nền | `#fdeee9` / `#fdeceb` | nền nhạt khi active/hover liên quan brand |
| Link blue (iView) | `#2d8cf0` | link, toggle, nút text nhấn |
| Link blue hover | `#1c6dd0` | hover link |
| Link blue tint | `#e8f4ff` | nền nhạt khối info/hướng dẫn (token `$c-link-tint`) |
| TikTok | `#010101` | badge nguồn TikTok |

### Trạng thái (status)
| Trạng thái | Text/đậm | Nền nhạt |
|---|---|---|
| Done / success | `#19be6b` (hoặc `#18a058`) | `#e8faf0` |
| Error / danger | `#ed4014` (hoặc `#d03050`) | `#fdecee` / `#fdeceb` |
| Pending / warning | `#ff9900` (hoặc `#d98500`) | `#fff6e6` |
| Archived / neutral | `#8a8f99` | `#f1f2f4` |

### Văn bản & nền (neutral)
| Token | Hex | Dùng cho |
|---|---|---|
| Text mạnh | `#1f2329` | tiêu đề, số liệu, tên |
| Text thường | `#515a6e` | nội dung phụ, metric |
| Text muted | `#8a8f99` | label, meta, mô tả |
| Text placeholder | `#b0b4bb` | empty state, ghi chú mờ |
| Nền card | `#fff` | thẻ, panel |
| Surface nhạt | `#f4f5f7` / `#f8f9fb` | hover row, khối metric, chip nền |
| Border | `#eef0f3` / `#e0e3e8` | viền card |
| Border input | `#dcdfe6` | viền field |
| Nền video/thumb | `#1f2329` / `#000` | nền media |

> **Legacy:** `app.css` còn dùng palette Element-UI cũ (`#409EFF`, `#67C23A`, `#E6A23C`, `#F56C6C`, `#909399`). KHÔNG dùng cho UI mới — đó là di sản. UI mới theo palette iView ở trên.

---

## 4. Spacing, radius, shadow, motion

**Spacing** — bội số của 2/4, gap-based (`gap` thay vì margin chồng chéo):
`2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 24` px. Padding card chuẩn `14–16px`, padding view `16–24px`.

**Border radius:**
| px | Dùng cho |
|---|---|
| `4px` | badge nhỏ, tag overlay |
| `6px` | ảnh nhỏ, chip id |
| `8px` | input, list item, chip, khối metric, thumb |
| `12px` | card / panel / stat |
| `14px` | card lớn (Compose) |
| `999px` | pill / badge tròn |
| `50%` | avatar / dot |

**Shadow:**
- Card mặc định: `0 4px 16px rgba(17, 24, 39, 0.06)`
- Card lớn: `0 6px 24px rgba(17, 24, 39, 0.08)`
- Hover nâng: `0 8px 22px rgba(17, 24, 39, 0.08)` + `transform: translateY(-1px)`

**Motion** — luôn nhẹ, dùng `ease`:
- Hover/opacity/màu: `0.15s ease`
- Transform/shadow card: `0.18s ease`
- Liệt kê rõ property: `transition: box-shadow 0.18s ease, border-color 0.18s ease, transform 0.18s ease;`

**Typography:**
| Vai trò | size | weight |
|---|---|---|
| Tiêu đề view | `20px` | `700` |
| Tiêu đề panel | `15px` | `600` |
| Số liệu (stat value) | `24px` | `700` |
| Nội dung / caption | `14px` | `600` (nhấn) / `400` |
| Meta / label / chip | `12–13px` | `500–600` |
| Ghi chú mờ | `11px` | — |

---

## 5. Layout

- **Flexbox + `gap`** là mặc định (không float, không margin hack). `float-*` trong `app.css` là legacy.
- Layout 2 cột: sidebar cố định (`width: 280px; flex-shrink: 0`) + main co giãn (`flex: 1; min-width: 0`).
- Card pattern chuẩn: `background:#fff; border-radius:12px; box-shadow:0 4px 16px rgba(17,24,39,0.06); padding:16px`.
- Text dài → `min-width: 0` + ellipsis (`white-space:nowrap; overflow:hidden; text-overflow:ellipsis`) hoặc `-webkit-line-clamp` cho nhiều dòng.
- Status indicator: dải màu trái card qua `&::before` (`width:4px`) đổi màu theo `is-*`.

**Responsive:** mobile-first khi cần, breakpoint dùng trong codebase: `@media (max-width: 860px)` → sidebar `width:100%`, body `flex-direction:column`.

---

## 6. i18n (bắt buộc)

- **MỌI text hiển thị** dùng `$t('KEY')`, KHÔNG hardcode chuỗi UI trong template.
- Key viết HOA, namespace theo feature (vd `SHOPEE_VIDEO_DASH_*`).
- Số/tiền format theo locale VN: `toLocaleString('vi-VN')`, hậu tố `đ`.

---

## 7. Component & code style (UI-liên quan)

- **Vue 2 Options API only** — không Composition API.
- **Braces bắt buộc** cho mọi `if`; **không ternary**; mỗi điều kiện một dòng (theo `codebase-rules`).
- **Không inline comment** mô tả code; type bằng JSDoc đặt ở `src/app/types/`.
- **PascalCase** cho tên component, **camelCase** cho props.
- Ưu tiên component iView (`Button type="primary|text|error|default" size="small"`, `Modal`, `Poptip confirm`, `Spin`, `RadioGroup type="button"`).
- Empty/loading/error state là bắt buộc cho list: empty → icon + text mờ; loading → `<Spin />`; error → message qua `$Message`.
- Feedback hành động qua `this.$Message.success|error|warning|info(this.$t('...'))`.

---

## 8. Checklist khi làm UI mới

- [ ] Style trong SFC `<style lang="scss" scoped>`, không nhét vào `app.css`.
- [ ] Class theo BEM + prefix feature, state dùng `is-*`.
- [ ] Chỉ dùng color/radius/shadow/spacing token ở mục 3–4 (palette iView, KHÔNG palette Element-UI legacy).
- [ ] Layout flex + `gap`; card `#fff` + radius 12px + shadow chuẩn.
- [ ] Mọi text qua `$t()`; tiền/số format `vi-VN`.
- [ ] Có empty / loading / error state.
- [ ] Override iView bằng `.ivu-*` suffix, KHÔNG `!important`.
- [ ] Transition nhẹ (`0.15–0.18s ease`), hover có phản hồi.
- [ ] Responsive ở `max-width: 860px` nếu là layout nhiều cột.
