---
# System prepended metadata

title: B2B 命名規則

---

# 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)