# B2B 命名規則
[toc]
## 圖片命名規則
#### 基本規則
* 前綴依據圖片的功用進行分類
* 連接使用底線"_"
#### 例
* icon_xxx ( 圖示類(svg)、小型提示圖 )
* banner_xxx ( 輪播圖 或 實體圖 )
* entry_xxx ( 入口圖 ( index、live、slot、virtualSports) )
* bg_xxx ( 背景圖 )
* kv_xxx ( 主視覺圖 )
* img_xxx ( 定義不明的雜圖 ( 善用"_"加上使用說明 ) )
---
## 使用 unocss 套用 svg 及換色
==icon-img-圖片url==
```htmlembedded
<div class='icon-img-/images/Promotion/icon_arrow.svg'></div>
```
==icon-color-顏色==
```htmlembedded
// Normal Colors
<div class='icon-color-red'></div>
// Hex Colors
<div class='icon-color-#456'></div>
// Theme Colors
<div class='icon-color-text.onPrimary'></div>
// Linear Gradient
<div class='icon-color-linear-gradient(yellow,red)'></div>
// Linear Gradient 漸層方向、多顏色、顏色占比
// 字串間不得留空白,
// to right -> to_right
// red 50% -> red_50%
<div class='linear-gradient(to_right,text.onSecondary_50%,red,text.onPrimary_70%,blue)'></div>
```
### convertColor
```js=
const convertColor = (color, theme) => {
/**
* 取得顏色
* @param {*} color
* @returns
*/
const getColor = (color) => {
color = color.trim()
const themeColor = convertThemeColor(color)
//color red = { 100:#000000, 200:#111111 }
if(typeof(themeColor) === 'object') return color
return themeColor ? themeColor : color
}
/**
* themeColor 轉換成色碼
* @param {*} color
* @returns hex || undefined
*/
const convertThemeColor = (color) => {
return color.split('.').reduce((acc, curr) => {
return acc[curr]
}, theme.colors)
}
/**
* 提取 linear-gradient 的參數
* @param color linear-gradient(text.onSecondary_50%, red)
* @returns [ '100deg', '#text.onSecondary 50%', 'red' ]
*/
const extractLinearColorParams = (color) => {
const reg = /^linear\-gradient\((.*)\)$/g
const params = [...color.matchAll(reg)][0][1].split(',')
return params
}
/**
* 將 params 中的 themeColor 轉換成色碼
* @param params [ '100deg', '#text.onSecondary_50%', 'red' ]
* @returns [ '100deg', '#33dd22 50%', 'red' ]
*/
const purifyParams = (params) => {
return params.map((item, index) => {
if (index === 0 && params.length > 2) return item.replace('_',' ')
const splitArr = item.split('_')
if(splitArr.length === 1) return getColor(splitArr[0])
return `${getColor(splitArr[0])} ${splitArr[1]}`
})
}
/**
* 將 params 組合成 linear-gradient
* @param params [ '100deg', '#33dd22_50%', 'red' ]
* @returns linear-gradient(100deg,#33dd22 50%,red)
*/
const makeLinearColor = (params) => {
return `linear-gradient(${params.join(',')})`
}
//execute here!!
if (color.includes('linear-gradient')) {
const params = extractLinearColorParams(color)
const cleanParams = purifyParams(params)
const LinearColor = makeLinearColor(cleanParams)
return LinearColor
}
return getColor(color)
}
```
### TestCase
```js=
const theme = {
colors: {
primary: '#000000',
alert: '#aa2266',
text: {
onPrimary: '#123456',
onSecondary: '#ffffff',
onAlert: '#112233'
},
bg: {
primary: {
onMain: '#333333',
onSecondary: '#444444'
}
}
}
}
//[[測資,期望結果],..[]]
const testCase = [
['red', 'red'],
['yellow', 'yellow'],
['#ffffff', '#ffffff'],
['#123456', '#123456'],
['text.onAlert', '#112233'],
['bg.primary.onSecondary','#444444'],
['linear-gradient(text.onSecondary_50%,blue)', 'linear-gradient(#ffffff 50%,blue)'],
['linear-gradient(#000000,blue)', 'linear-gradient(#000000,blue)'],
['linear-gradient(#000000,alert)', 'linear-gradient(#000000,#aa2266)'],
['linear-gradient(to_right,text.onAlert,alert)', 'linear-gradient(to right,#112233,#aa2266)'],
['linear-gradient(90deg,red_77%,#112233)', 'linear-gradient(90deg,red 77%,#112233)'],
[
'linear-gradient(90deg,bg.primary.onMain_77%, text.onAlert)',
'linear-gradient(90deg,#333333 77%,#112233)'
],
[
'linear-gradient(red,#ccc,primary,bg.primary.onMain,text.onAlert)',
'linear-gradient(red,#ccc,#000000,#333333,#112233)'
],
[
'linear-gradient(180deg,#ccc_10%,primary_30%,bg.primary.onMain_50%, text.onAlert)',
'linear-gradient(180deg,#ccc 10%,#000000 30%,#333333 50%,#112233)'
],
[
'linear-gradient(to_right,text.onSecondary_50%,red,text.onPrimary_70%,blue)',
'linear-gradient(to right,#ffffff 50%,red,#123456 70%,blue)'
]
]
```
### Test function
```js=
const test = (cb, testCase) => {
let endIndex = 0
const start = performance.now()
const bool = testCase.every((element, index) => {
endIndex = index
return cb(element[0], theme) === element[1]
})
const end = performance.now()
if (bool)
return (
`status: ${bool}\n` +
`totalTestCase: ${testCase.length}\n` +
`totalTime: ${Math.round((end - start) * 1000)}ms\n` +
`avgTime: ${Math.round(Math.round((end - start) * 1000) / testCase.length)}ms`
)
else
return (
`status: ${bool}\n` +
`terminate index: ${endIndex}\n` +
`terminate case: ${testCase[endIndex]}\n` +
`totalTestCase: ${testCase.length}\n`
)
}
```
### Test Result
```js=
console.log(test(convertColor, testCase))
status: true
totalTestCase: 15
totalTime: 992ms
avgTime: 66ms
```
## Text 命名規則 (20230315)
依照 Material Design Guidelines 規則進行以下定義:
**文字類型**
* display ( 用於展示在頁面的大型文字( eg: Welcome! ) )
* headline ( 頁面標題 )
* title ( 分區標題 )
* body ( 內文、提示字等 )
* label ( 標籤、小標等 )
**字體粗細命名 ( 開頭為 ( font-weight )):**
* 100: Thin
* 200: Extra Light
* 300: Light
* 400: Regular
* 500: Medium
* 600: Semi Bold
* 700: Bold
* 800: Extra Bold
* 900: Black
**字體大小命名:**
由大到小
* lg
* md
* (空)
* sm
* xs
最多五種分類。
:::info
文字類型 - 文字粗細 - 文字大小
label-regular-lg
:::
實例:
```js=
{
'head-line': 'text-24px font-600',
'label-bold-lg': 'text-20px font-600',
'label-bold-md': 'text-18px font-600',
'label-bold': 'text-15px font-600',
'label-regular-lg': 'text-20px font-400',
'label-regular-md': 'text-18px font-400',
'label-regular': 'text-15px font-400',
'body-bold-md': 'text-14px font-600',
'body-regular-md': 'text-14px font-400',
'body-regular': 'text-12px font-400'
},
```
[Material Design Guideline - font setting](https://m3.material.io/styles/typography/type-scale-tokens)
## Color 命名規則 (20230314)
### Global
依照主色 ( 品牌色 )、輔色、重複使用頻率高~低,分成五種名稱。
:::info
附註: 因為設計並不會依照 designguide lines 規則命名,故下方的 pick color 的位置僅供參考,主要還是已使用顏色的頻率為主進行命名。
:::
* **Primary**
方向: 品牌 logo 用色,主要被用於按鈕 ( 用戶積極行為 eg,購買、送出...等 ) ) 採用色、主要 active 色。
* **Seconday**
方向: 作為主色輔助讓顏色的應用不會太單調,比主色略暗或亮。可以參考被用於 tab bar 被選取色、用於選單內的 icon,頁面內 segement control 的互動色。
* **Tertiary**
方向: 通常用途做為提示色。可以參考被用於 "標籤 (label)"、"info icon"、"公告背景色" 等。
* **Quaternary**
方向: 依照被使用頻率進行命名。
* **Quinary**
方向: 依照被使用頻率進行命名。
其餘分散的顏色( 重複性極低 || 文字&背景皆有使用 )前綴皆用 ==inverse+數字== 進行命名。
```js=
// 舉例
primary: '#ECCA91', //
secondary: '#7D7C88', //
tertiary: '#008FE0', //
quaternary: '#DEB64F', //
quinary: '#434553', //
inverse: {
'01': '#AE68E5', //
'02': '#56CB00', //
'03': '#1B1920', //
},
```
### Background(bg)、text 等元件
依照使用頻率分成:
* element-asPrimary
* element-asSeconday
* element-asTertiary
其餘分散的顏色( 重複性較相對低 )前綴皆用 ==element-asInverse+數字== 進行命名。
```js=
bg: {
asPrimary: '#202127', //
asSecondary: '#18181D', //
asTertiary: '#292A34', //
asInverse: {
'01': '#353743', //
'02': '#20A7F3', //
'03': '#2B2B3A', //
'04': '#18191E' //
}
},
text: {
asPrimary: '#FFFFFF',
asSecondary: '#CCCCCC', //
asTertiary: '#434359', //
asInverse: {
'01': '#FEBB29', //
'02': '#B5B5B5' //
}
}
```
### 固定狀態
依照 bootstrap||material design guideline 規則,整理出部分形象已固定的狀態,分別為:
* alert
* confirm
* info
```js=
alert: '#EA3636',
confirm: '#56CB00',
info: '#DEB64F'
```
### Neutral(非必要)
依照 material design guideline 規則,將所有屬於灰階的顏色獨立,原因:灰階顏色被應用範圍相對其他顏色較廣起不固定,故在 UI 劃分時會將灰階格外分類。
:::warning
Neutral 的分類與其他分類相比又更模糊,建議在設計稿已確定的前提下進行,會比較有效率。
:::
```js=
neutral: {
// from dark to light
'000': '#000000',
'050': '#353535', //
'055': '#444444',
'060': '#555555', //
'070': '#A6A6A6', //
'080': '#B5B5B5', //
'090': '#E1E1E1',
'100': '#ffffff'
}
```
新增 guidelines 公定的 10 階灰階。
```js=
neutral: {
// from dark to light
'000': '#000000',
'010': '#1A1A1A',
'020': '#333333',
'030': '#4D4D4D',
'040': '#666666',
'050': '#808080',
'060': '#999999',
'070': '#B3B3B3',
'080': '#CCCCCC',
'090': '#E5E5E5',
'100': '#ffffff'
}
```
## 使用 ShortCut 管理 Global 元件進行換色
### BackgroundColor
依照共用背景色命名,區塊由大到小。
規則:
**bg-'element'-'detail'**
```js=
// 使用頻率舉例
'bg-global': 'bg-transparent', // 全站底色
'bg-nav': 'bg-neutral-000/40', // 導覽列底色
'bg-popup-outer': 'bg-neutral-000/70', // 彈跳視窗外部背景色
'bg-popup-content': 'bg-bg-asTertiary/90', // 彈跳視窗背景色
'bg-layoutSide-content': 'bg-bg-as-secondary/90' // layout背景色
```
### Nav
對導覽列( navigationbar )**內**的 icon 與 文字進行命名。
規則:
**nav-list-'status||element'**
```js=
// Nav 舉例
'nav-list-hover': 'c-primary bg-primary', // hover 狀態
'nav-list-item': 'c-secondary', // 單個 nav 背景
'nav-list-icon': 'bg-secondary' // 單個 nav 文字
```
### Button
規則:
1. 依照被使用頻率的命名規則:
**btn-/primary|secondary|tertiary/-/default|disable/。**
```js=
// 使用頻率舉例
'btn-primary': 'bg-tertiary c-neutral-100 hover:bg-bg-asInverse-02',
'btn-primary-disable': 'bg-tertiary/50 c-neutral-100',
'btn-secondary': 'bg-bg-asTertiary c-secondary hover:bg-bg-asInverse-01',
'btn-secondary-disable': 'bg-bg-asTertiary/50 c-secondary',
```
2. 其餘不適用頻率規則的共用元件
**btn-inverse-'功能名稱'**
```js=
// 其餘共用元件
'btn-inverse-close': 'bg-quinary hover:bg-neutral-100/40',
'btn-inverse-login': 'c-text-asPrimary/70 bg-gradient-to-b from-gradient-asSecondary-from to-gradient-asSecondary-to hover:bg-gradient-asSecondary-to hover:bg-none',
'btn-inverse-register': 'c-text-asPrimary/70 bg-gradient-to-b from-gradient-asInverse-01-from to-gradient-asInverse-01-to hover:bg-gradient-asInverse-01-to hover:bg-none',
'btn-inverse-guestMail': 'bg-gradient-to-b from-gradient-asTertiary-from to-gradient-asTertiary-to c-inverse-16 hover:bg-inverse-09 hover:bg-none',
'btn-inverse-logout': '',// 009
'btn-inverse-deposit': '',// 009
'btn-inverse-withdraw': 'bg-gradient-to-b from-gradient-asSecondary-from to-gradient-asSecondary-to hover:bg-gradient-asSecondary-to hover:bg-none',
'btn-inverse-memberpoint': 'bg-gradient-to-b from-#44256F to-#59259B hover:bg-#59259B hover:bg-none',
'btn-inverse-userInfo': 'bg-gradient-to-b from-gradient-asPrimary-from to-gradient-asPrimary-to hover:bg-gradient-asPrimary-to hover:bg-none',
```
### Input
* 依照 input 的結構進行命名與劃分,wrapper 代表包在 input 外的 div , content 代表 input 本身。
* 為了消除每個 input 都有預設的 focus 樣式,將 reset 的樣式也一同寫進 input 的 shortcut 內。
規則:
1. 依照被使用頻率的命名規則:
**input-/primary|secondary|tertiary/-描述**
2. 其餘不適用頻率規則的共用元件
**input-inverse-'描述'**
```js=
// 使用頻率舉例
'input-primary-wrapper': 'bg-bg-as-secondary/70 focus-within:outline focus-within:outline-1px focus-within:outline-tertiary hover:outline hover:outline-1px hover:outline-tertiary',
'input-primary-content': 'c-secondary bg-transparent focus-outline focus-outline-1px focus-outline-black focus-visible:outline-0! focus-visible:outline-0! placeholder-neutral-050',
'input-primary-label': 'c-text-asSecondary',
'input-error-tip': 'bg-inverse-07 c-secondary',
'checkBox-wrapper': 'bg-bg-as-secondary/70'
```
### Icon
規則:
* 依照 icon 的圖示與意義直接進行命名。
* 依照 bootstrap 與 Material DesignGuidelines , 除了 /confirm|alert|info/ 以外,其餘皆加前綴 inverse。
**icon-inverse-"圖示名稱"**
```js=
// 使用頻率舉例
'icon-confirm': 'bg-confirm',
'icon-alert': 'bg-inverse-07',
'icon-info': 'bg-info',
'icon-inverse-close': 'bg-quinary',
'icon-inverse-guestmail': 'bg-secondary'
```
[參考: bootstrap](https://getbootstrap.com/docs/5.0/customize/color/)
[參考: Material Design Guideline](https://m3.material.io/styles/color/the-color-system/key-colors-tones)
## 附加
### 商城 B2B Moible 組件範例
[商城 B2B Moible 組件](https://hackmd.io/ysh9tfUiTD-rnOEFTIvyuQ?both)