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