feat(ui): Sidebar nav
@@ -8,7 +8,6 @@ const config: StorybookConfig = {
|
|||||||
"@storybook/addon-links",
|
"@storybook/addon-links",
|
||||||
"@storybook/addon-docs",
|
"@storybook/addon-docs",
|
||||||
"@storybook/addon-a11y",
|
"@storybook/addon-a11y",
|
||||||
"@storybook/addon-onboarding",
|
|
||||||
],
|
],
|
||||||
async viteFinal(config) {
|
async viteFinal(config) {
|
||||||
return mergeConfig(config, {
|
return mergeConfig(config, {
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="currentColor">
|
||||||
<path d="M27 38H6V17H10V13H13.5V9H37.5V13H41V24H27V27H34V31H30.5V34.5H27V38ZM16.5 20.5H20V17H16.5V20.5Z" fill="black"/>
|
<path d="M27 38H6V17H10V13H13.5V9H37.5V13H41V24H27V27H34V31H30.5V34.5H27V38ZM16.5 20.5H20V17H16.5V20.5Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 226 B After Width: | Height: | Size: 221 B |
@@ -1,25 +1,25 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="35" height="42" viewBox="0 0 35 42" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="35" height="42" viewBox="0 0 35 42" fill="currentColor">
|
||||||
<rect y="6" width="6" height="6" fill="black"/>
|
<rect y="6" width="6" height="6"/>
|
||||||
<rect x="6" y="6" width="6" height="6" fill="black"/>
|
<rect x="6" y="6" width="6" height="6"/>
|
||||||
<rect x="12" y="6" width="6" height="6" fill="black"/>
|
<rect x="12" y="6" width="6" height="6"/>
|
||||||
<rect x="6" y="12" width="6" height="6" fill="black"/>
|
<rect x="6" y="12" width="6" height="6"/>
|
||||||
<rect x="18" y="18" width="6" height="6" fill="black"/>
|
<rect x="18" y="18" width="6" height="6"/>
|
||||||
<rect x="18" y="12" width="6" height="6" fill="black"/>
|
<rect x="18" y="12" width="6" height="6"/>
|
||||||
<rect x="12" y="24" width="6" height="6" fill="black"/>
|
<rect x="12" y="24" width="6" height="6"/>
|
||||||
<rect x="12" y="18" width="6" height="6" fill="black"/>
|
<rect x="12" y="18" width="6" height="6"/>
|
||||||
<rect x="12" y="12" width="6" height="6" fill="black"/>
|
<rect x="12" y="12" width="6" height="6"/>
|
||||||
<rect width="6" height="6" fill="black"/>
|
<rect width="6" height="6"/>
|
||||||
<rect x="6" width="6" height="6" fill="black"/>
|
<rect x="6" width="6" height="6"/>
|
||||||
<rect x="24" y="18" width="6" height="6" fill="black"/>
|
<rect x="24" y="18" width="6" height="6"/>
|
||||||
<rect y="12" width="6" height="6" fill="black"/>
|
<rect y="12" width="6" height="6"/>
|
||||||
<rect x="6" y="18" width="6" height="6" fill="black"/>
|
<rect x="6" y="18" width="6" height="6"/>
|
||||||
<rect y="18" width="6" height="6" fill="black"/>
|
<rect y="18" width="6" height="6"/>
|
||||||
<rect y="24" width="6" height="6" fill="black"/>
|
<rect y="24" width="6" height="6"/>
|
||||||
<rect y="30" width="6" height="6" fill="black"/>
|
<rect y="30" width="6" height="6"/>
|
||||||
<rect y="36" width="6" height="6" fill="black"/>
|
<rect y="36" width="6" height="6"/>
|
||||||
<rect x="6" y="24" width="6" height="6" fill="black"/>
|
<rect x="6" y="24" width="6" height="6"/>
|
||||||
<rect x="18" y="24" width="6" height="6" fill="black"/>
|
<rect x="18" y="24" width="6" height="6"/>
|
||||||
<rect x="24" y="24" width="6" height="6" fill="black"/>
|
<rect x="24" y="24" width="6" height="6"/>
|
||||||
<rect x="29" y="24" width="6" height="6" fill="black"/>
|
<rect x="29" y="24" width="6" height="6"/>
|
||||||
<rect x="6" y="30" width="6" height="6" fill="black"/>
|
<rect x="6" y="30" width="6" height="6"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -1,3 +1,3 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="currentColor">
|
||||||
<path d="M20.2002 12.7998H23V15.5996H25.8008V14.2002H28.6006V10H34.2002V12.7998H37V15.5996H39.8008V24H37V26.7998H34.2002V29.5996H31.4004V32.4004H28.6006V35.2002H25.8008V38H23V35.2002H20.2002V32.4004H17.4004V29.5996H14.6006V26.7998H11.8008V24H9V15.5996H11.8008V12.7998H14.6006V10H20.2002V12.7998Z" fill="black"/>
|
<path d="M20.2002 12.7998H23V15.5996H25.8008V14.2002H28.6006V10H34.2002V12.7998H37V15.5996H39.8008V24H37V26.7998H34.2002V29.5996H31.4004V32.4004H28.6006V35.2002H25.8008V38H23V35.2002H20.2002V32.4004H17.4004V29.5996H14.6006V26.7998H11.8008V24H9V15.5996H11.8008V12.7998H14.6006V10H20.2002V12.7998Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 413 B |
@@ -1,3 +1,3 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="currentColor">
|
||||||
<path d="M38.666 5V39.667H38.667V5H43V44H4V5H38.666ZM12.666 35.334H16.999V31H12.666V35.334ZM29.999 35.334H34.333V31H29.999V35.334ZM21.333 26.667H25.666V22.334H21.333V26.667ZM12.666 18H16.999V13.667H12.666V18ZM29.999 18H34.333V13.667H29.999V18Z" fill="black"/>
|
<path d="M38.666 5V39.667H38.667V5H43V44H4V5H38.666ZM12.666 35.334H16.999V31H12.666V35.334ZM29.999 35.334H34.333V31H29.999V35.334ZM21.333 26.667H25.666V22.334H21.333V26.667ZM12.666 18H16.999V13.667H12.666V18ZM29.999 18H34.333V13.667H29.999V18Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 366 B After Width: | Height: | Size: 361 B |
@@ -1,3 +1,3 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="currentColor">
|
||||||
<path d="M38 42H10V38H6V10H10V6H38V10H42V38H38V42ZM18 32H30V28H18V32ZM14 28H18V24H14V28ZM30 28H34V24H30V28ZM16 20H20V16H16V20ZM28 20H32V16H28V20Z" fill="black"/>
|
<path d="M38 42H10V38H6V10H10V6H38V10H42V38H38V42ZM18 32H30V28H18V32ZM14 28H18V24H14V28ZM30 28H34V24H30V28ZM16 20H20V16H16V20ZM28 20H32V16H28V20Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 268 B After Width: | Height: | Size: 263 B |
@@ -1,3 +1,3 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="currentColor">
|
||||||
<path d="M42 42H14V38H38V14H42V42ZM34 6V34H6V6H34ZM18 18H14V22H18V26H22V22H26V18H22V14H18V18Z" fill="black"/>
|
<path d="M42 42H14V38H38V14H42V42ZM34 6V34H6V6H34ZM18 18H14V22H18V26H22V22H26V18H22V14H18V18Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 216 B After Width: | Height: | Size: 211 B |
@@ -1,13 +1,13 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="38" height="27" viewBox="0 0 38 27" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="38" height="27" viewBox="0 0 38 27" fill="currentColor">
|
||||||
<rect x="4.46155" y="4.15381" width="4.15385" height="4.15385" fill="black"/>
|
<rect x="4.46155" y="4.15381" width="4.15385" height="4.15385"/>
|
||||||
<rect x="29.3846" y="4.15381" width="4.15385" height="4.15385" fill="black"/>
|
<rect x="29.3846" y="4.15381" width="4.15385" height="4.15385"/>
|
||||||
<rect x="8.61539" width="4.15385" height="4.15385" fill="black"/>
|
<rect x="8.61539" width="4.15385" height="4.15385"/>
|
||||||
<rect x="33.5385" width="4.15385" height="4.15385" fill="black"/>
|
<rect x="33.5385" width="4.15385" height="4.15385"/>
|
||||||
<rect x="0.307678" width="4.15385" height="4.15385" fill="black"/>
|
<rect x="0.307678" width="4.15385" height="4.15385"/>
|
||||||
<rect x="25.2308" width="4.15385" height="4.15385" fill="black"/>
|
<rect x="25.2308" width="4.15385" height="4.15385"/>
|
||||||
<rect x="0.307678" y="8.30762" width="4.15385" height="4.15385" fill="black"/>
|
<rect x="0.307678" y="8.30762" width="4.15385" height="4.15385"/>
|
||||||
<rect x="25.2308" y="8.30762" width="4.15385" height="4.15385" fill="black"/>
|
<rect x="25.2308" y="8.30762" width="4.15385" height="4.15385"/>
|
||||||
<rect x="8.61539" y="8.30762" width="4.15385" height="4.15385" fill="black"/>
|
<rect x="8.61539" y="8.30762" width="4.15385" height="4.15385"/>
|
||||||
<rect x="33.5385" y="8.30762" width="4.15385" height="4.15385" fill="black"/>
|
<rect x="33.5385" y="8.30762" width="4.15385" height="4.15385"/>
|
||||||
<rect x="4" y="23" width="30" height="4" fill="black"/>
|
<rect x="4" y="23" width="30" height="4"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 936 B After Width: | Height: | Size: 801 B |
@@ -1,3 +1,3 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="currentColor">
|
||||||
<path d="M39.2002 39.2002H43V43H39.2002V39.2021H35.3994V35.4014H39.2002V39.2002ZM27.7998 8.80078H31.5996V31.6016H27.7998V35.4004H12.6006V12.6016H20.2002V8.80078H12.6006V5H27.7998V8.80078ZM35.4004 35.4004H31.6006V31.6006H35.4004V35.4004ZM12.5996 12.5996H8.7998V20.2002H12.5996V31.6016H8.7998V27.8008H5V12.5996H8.7998V8.80078H12.5996V12.5996ZM35.4004 27.8008H31.6006V12.5996H35.4004V27.8008Z" fill="black"/>
|
<path d="M39.2002 39.2002H43V43H39.2002V39.2021H35.3994V35.4014H39.2002V39.2002ZM27.7998 8.80078H31.5996V31.6016H27.7998V35.4004H12.6006V12.6016H20.2002V8.80078H12.6006V5H27.7998V8.80078ZM35.4004 35.4004H31.6006V31.6006H35.4004V35.4004ZM12.5996 12.5996H8.7998V20.2002H12.5996V31.6016H8.7998V27.8008H5V12.5996H8.7998V8.80078H12.5996V12.5996ZM35.4004 27.8008H31.6006V12.5996H35.4004V27.8008Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 507 B |
@@ -1,8 +1,8 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="23" viewBox="0 0 36 23" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="23" viewBox="0 0 36 23" fill="currentColor">
|
||||||
<rect x="27" width="22.5" height="4.5" transform="rotate(90 27 0)" fill="black"/>
|
<rect x="27" width="22.5" height="4.5" transform="rotate(90 27 0)"/>
|
||||||
<rect x="31.5" y="4.5" width="13.5" height="4.5" transform="rotate(90 31.5 4.5)" fill="black"/>
|
<rect x="31.5" y="4.5" width="13.5" height="4.5" transform="rotate(90 31.5 4.5)"/>
|
||||||
<rect x="36" y="9" width="4.5" height="4.5" transform="rotate(90 36 9)" fill="black"/>
|
<rect x="36" y="9" width="4.5" height="4.5" transform="rotate(90 36 9)"/>
|
||||||
<rect width="22.5" height="4.5" transform="matrix(-4.37114e-08 1 1 4.37114e-08 9 0)" fill="black"/>
|
<rect width="22.5" height="4.5" transform="matrix(-4.37114e-08 1 1 4.37114e-08 9 0)"/>
|
||||||
<rect width="13.5" height="4.5" transform="matrix(-4.37114e-08 1 1 4.37114e-08 4.5 4.5)" fill="black"/>
|
<rect width="13.5" height="4.5" transform="matrix(-4.37114e-08 1 1 4.37114e-08 4.5 4.5)"/>
|
||||||
<rect width="4.5" height="4.5" transform="matrix(-4.37114e-08 1 1 4.37114e-08 0 9)" fill="black"/>
|
<rect width="4.5" height="4.5" transform="matrix(-4.37114e-08 1 1 4.37114e-08 0 9)"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 694 B After Width: | Height: | Size: 624 B |
@@ -1,3 +1,3 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="currentColor">
|
||||||
<path d="M39.4004 31.2002H35.7998V34.7998H32.2002V38.3994H28.5996V42H25V38.3994H21.4004V34.7998H17.7998V31.2002H14.2002V27.6006H39.4004V31.2002ZM28.5996 13.2002H32.2002V16.7998H35.7998V20.3994H39.4004V24H43V27.5996H10.5996V24H7V9.60059H28.5996V13.2002ZM14.2002 13.2002V16.7998H17.7998V13.2002H14.2002ZM25 9.59961H7V6H25V9.59961Z" fill="black"/>
|
<path d="M39.4004 31.2002H35.7998V34.7998H32.2002V38.3994H28.5996V42H25V38.3994H21.4004V34.7998H17.7998V31.2002H14.2002V27.6006H39.4004V31.2002ZM28.5996 13.2002H32.2002V16.7998H35.7998V20.3994H39.4004V24H43V27.5996H10.5996V24H7V9.60059H28.5996V13.2002ZM14.2002 13.2002V16.7998H17.7998V13.2002H14.2002ZM25 9.59961H7V6H25V9.59961Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 451 B After Width: | Height: | Size: 446 B |
@@ -1,3 +1,3 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="currentColor">
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.8 0H28.4V9.6H18.8V0ZM11.6 12H35.6V16.8H30.8V33.6V48H26V33.6H21.2V48H16.4V33.6V16.8H11.6V12ZM6.8 7.2V12H11.6V7.2H6.8ZM6.8 7.2L2 7.2V2.4H6.8V7.2ZM40.4 7.2V12H35.6V7.2H40.4ZM40.4 7.2L40.4 2.4H45.2V7.2L40.4 7.2Z" fill="black"/>
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.8 0H28.4V9.6H18.8V0ZM11.6 12H35.6V16.8H30.8V33.6V48H26V33.6H21.2V48H16.4V33.6V16.8H11.6V12ZM6.8 7.2V12H11.6V7.2H6.8ZM6.8 7.2L2 7.2V2.4H6.8V7.2ZM40.4 7.2V12H35.6V7.2H40.4ZM40.4 7.2L40.4 2.4H45.2V7.2L40.4 7.2Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 383 B After Width: | Height: | Size: 378 B |
35
pkgs/clan-app/ui/package-lock.json
generated
@@ -15,6 +15,7 @@
|
|||||||
"@modular-forms/solid": "^0.25.1",
|
"@modular-forms/solid": "^0.25.1",
|
||||||
"@solid-primitives/storage": "^4.3.2",
|
"@solid-primitives/storage": "^4.3.2",
|
||||||
"@solidjs/router": "^0.15.3",
|
"@solidjs/router": "^0.15.3",
|
||||||
|
"@solidjs/testing-library": "^0.8.10",
|
||||||
"@tanstack/eslint-plugin-query": "^5.51.12",
|
"@tanstack/eslint-plugin-query": "^5.51.12",
|
||||||
"@tanstack/solid-query": "^5.76.0",
|
"@tanstack/solid-query": "^5.76.0",
|
||||||
"solid-js": "^1.9.7",
|
"solid-js": "^1.9.7",
|
||||||
@@ -126,7 +127,6 @@
|
|||||||
"version": "7.27.1",
|
"version": "7.27.1",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
|
||||||
"integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
|
"integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": "^7.27.1",
|
"@babel/helper-validator-identifier": "^7.27.1",
|
||||||
@@ -268,7 +268,6 @@
|
|||||||
"version": "7.27.1",
|
"version": "7.27.1",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
|
||||||
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
|
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -366,7 +365,6 @@
|
|||||||
"version": "7.27.6",
|
"version": "7.27.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
|
||||||
"integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==",
|
"integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -2037,6 +2035,27 @@
|
|||||||
"solid-js": "^1.8.6"
|
"solid-js": "^1.8.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@solidjs/testing-library": {
|
||||||
|
"version": "0.8.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@solidjs/testing-library/-/testing-library-0.8.10.tgz",
|
||||||
|
"integrity": "sha512-qdeuIerwyq7oQTIrrKvV0aL9aFeuwTd86VYD3afdq5HYEwoox1OBTJy4y8A3TFZr8oAR0nujYgCzY/8wgHGfeQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@testing-library/dom": "^10.4.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@solidjs/router": ">=0.9.0",
|
||||||
|
"solid-js": ">=1.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@solidjs/router": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@storybook/addon-a11y": {
|
"node_modules/@storybook/addon-a11y": {
|
||||||
"version": "9.0.12",
|
"version": "9.0.12",
|
||||||
"resolved": "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-9.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-9.0.12.tgz",
|
||||||
@@ -2305,7 +2324,6 @@
|
|||||||
"version": "10.4.0",
|
"version": "10.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
|
||||||
"integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
|
"integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.10.4",
|
"@babel/code-frame": "^7.10.4",
|
||||||
@@ -2409,7 +2427,6 @@
|
|||||||
"version": "5.0.4",
|
"version": "5.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||||
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/babel__core": {
|
"node_modules/@types/babel__core": {
|
||||||
@@ -3161,7 +3178,6 @@
|
|||||||
"version": "5.3.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
|
||||||
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dequal": "^2.0.3"
|
"dequal": "^2.0.3"
|
||||||
@@ -3989,7 +4005,6 @@
|
|||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||||
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
@@ -4011,7 +4026,6 @@
|
|||||||
"version": "0.5.16",
|
"version": "0.5.16",
|
||||||
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
||||||
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/dom-serializer": {
|
"node_modules/dom-serializer": {
|
||||||
@@ -5323,7 +5337,6 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
@@ -5644,7 +5657,6 @@
|
|||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
|
||||||
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
|
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"lz-string": "bin/bin.js"
|
"lz-string": "bin/bin.js"
|
||||||
@@ -6505,7 +6517,6 @@
|
|||||||
"version": "27.5.1",
|
"version": "27.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
|
||||||
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": "^5.0.1",
|
"ansi-regex": "^5.0.1",
|
||||||
@@ -6520,7 +6531,6 @@
|
|||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
||||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
@@ -6622,7 +6632,6 @@
|
|||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/read-cache": {
|
"node_modules/read-cache": {
|
||||||
|
|||||||
@@ -67,6 +67,7 @@
|
|||||||
"@modular-forms/solid": "^0.25.1",
|
"@modular-forms/solid": "^0.25.1",
|
||||||
"@solid-primitives/storage": "^4.3.2",
|
"@solid-primitives/storage": "^4.3.2",
|
||||||
"@solidjs/router": "^0.15.3",
|
"@solidjs/router": "^0.15.3",
|
||||||
|
"@solidjs/testing-library": "^0.8.10",
|
||||||
"@tanstack/eslint-plugin-query": "^5.51.12",
|
"@tanstack/eslint-plugin-query": "^5.51.12",
|
||||||
"@tanstack/solid-query": "^5.76.0",
|
"@tanstack/solid-query": "^5.76.0",
|
||||||
"solid-js": "^1.9.7",
|
"solid-js": "^1.9.7",
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import type { Meta, StoryObj } from "@kachurun/storybook-solid";
|
|||||||
import { Button, ButtonProps } from "./Button";
|
import { Button, ButtonProps } from "./Button";
|
||||||
import { Component } from "solid-js";
|
import { Component } from "solid-js";
|
||||||
import { expect, fn, waitFor } from "storybook/test";
|
import { expect, fn, waitFor } from "storybook/test";
|
||||||
import { PlayFunctionContext } from "storybook/internal/csf";
|
|
||||||
import { StoryContext } from "@kachurun/storybook-solid-vite";
|
import { StoryContext } from "@kachurun/storybook-solid-vite";
|
||||||
|
|
||||||
const getCursorStyle = (el: Element) => window.getComputedStyle(el).cursor;
|
const getCursorStyle = (el: Element) => window.getComputedStyle(el).cursor;
|
||||||
@@ -150,7 +149,7 @@ export const Primary: Story = {
|
|||||||
hierarchy: "primary",
|
hierarchy: "primary",
|
||||||
onAction: fn(async () => {
|
onAction: fn(async () => {
|
||||||
// wait 500 ms to simulate an action
|
// wait 500 ms to simulate an action
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
// randomly fail to check that the loading state still returns to normal
|
// randomly fail to check that the loading state still returns to normal
|
||||||
if (Math.random() > 0.5) {
|
if (Math.random() > 0.5) {
|
||||||
throw new Error("Action failure");
|
throw new Error("Action failure");
|
||||||
@@ -159,6 +158,7 @@ export const Primary: Story = {
|
|||||||
},
|
},
|
||||||
parameters: {
|
parameters: {
|
||||||
test: {
|
test: {
|
||||||
|
// increase test timeout to allow for the loading action
|
||||||
mockTimers: true,
|
mockTimers: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -205,14 +205,17 @@ export const Primary: Story = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// wait for the action handler to finish
|
// wait for the action handler to finish
|
||||||
await waitFor(async () => {
|
await waitFor(
|
||||||
// the loading class should be removed
|
async () => {
|
||||||
await expect(button).not.toHaveClass("loading");
|
// the loading class should be removed
|
||||||
// the loader should be hidden
|
await expect(button).not.toHaveClass("loading");
|
||||||
await expect(loader.clientWidth).toEqual(0);
|
// the loader should be hidden
|
||||||
// the pointer should be normal
|
await expect(loader.clientWidth).toEqual(0);
|
||||||
await expect(getCursorStyle(button)).toEqual("pointer");
|
// the pointer should be normal
|
||||||
});
|
await expect(getCursorStyle(button)).toEqual("pointer");
|
||||||
|
},
|
||||||
|
{ timeout: 1500 },
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { splitProps, type JSX, createSignal, Show } from "solid-js";
|
import { splitProps, type JSX, createSignal } from "solid-js";
|
||||||
import cx from "classnames";
|
import cx from "classnames";
|
||||||
import { Typography } from "../Typography/Typography";
|
import { Typography } from "../Typography/Typography";
|
||||||
import { Button as KobalteButton } from "@kobalte/core/button";
|
import { Button as KobalteButton } from "@kobalte/core/button";
|
||||||
|
|||||||
15
pkgs/clan-app/ui/src/components/v2/Divider/Divider.css
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
div.divider {
|
||||||
|
@apply bg-inv-2;
|
||||||
|
|
||||||
|
&.inverted {
|
||||||
|
@apply bg-def-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.horizontal {
|
||||||
|
@apply w-full h-px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.vertical {
|
||||||
|
@apply h-full w-px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { Meta, StoryObj } from "@kachurun/storybook-solid";
|
||||||
|
import { Divider, DividerProps } from "@/src/components/v2/Divider/Divider";
|
||||||
|
|
||||||
|
const meta: Meta<DividerProps> = {
|
||||||
|
title: "Components/Divider",
|
||||||
|
component: Divider,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<DividerProps>;
|
||||||
|
|
||||||
|
export const Default: Story = {};
|
||||||
|
|
||||||
|
export const Horizontal: Story = {
|
||||||
|
args: {
|
||||||
|
orientation: "horizontal",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const HorizontalInverted: Story = {
|
||||||
|
args: {
|
||||||
|
inverted: true,
|
||||||
|
...Horizontal.args,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Vertical: Story = {
|
||||||
|
args: {
|
||||||
|
orientation: "vertical",
|
||||||
|
},
|
||||||
|
decorators: [
|
||||||
|
(Story: Story) => (
|
||||||
|
<div class="h-32 w-full">
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const VerticalInverted: Story = {
|
||||||
|
args: {
|
||||||
|
inverted: true,
|
||||||
|
...Vertical.args,
|
||||||
|
},
|
||||||
|
decorators: [...Vertical.decorators],
|
||||||
|
};
|
||||||
16
pkgs/clan-app/ui/src/components/v2/Divider/Divider.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import "./Divider.css";
|
||||||
|
import cx from "classnames";
|
||||||
|
|
||||||
|
export type Orientation = "horizontal" | "vertical";
|
||||||
|
|
||||||
|
export interface DividerProps {
|
||||||
|
inverted?: boolean;
|
||||||
|
orientation?: Orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Divider = (props: DividerProps) => {
|
||||||
|
const inverted = props.inverted || false;
|
||||||
|
const orientation = props.orientation || "horizontal";
|
||||||
|
|
||||||
|
return <div class={cx("divider", orientation, { inverted: inverted })} />;
|
||||||
|
};
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { Meta, StoryObj } from "@kachurun/storybook-solid";
|
import type { Meta, StoryObj, StoryContext } from "@kachurun/storybook-solid";
|
||||||
import { Component, For } from "solid-js";
|
import { Component, For } from "solid-js";
|
||||||
import Icon, { IconProps, IconVariant } from "./Icon";
|
import Icon, { IconProps, IconVariant } from "./Icon";
|
||||||
|
import cx from "classnames";
|
||||||
|
|
||||||
const iconVariants: IconVariant[] = [
|
const iconVariants: IconVariant[] = [
|
||||||
"ClanIcon",
|
"ClanIcon",
|
||||||
@@ -59,6 +60,13 @@ const IconExamples: Component<IconProps> = (props) => (
|
|||||||
const meta: Meta<IconProps> = {
|
const meta: Meta<IconProps> = {
|
||||||
title: "Components/Icon",
|
title: "Components/Icon",
|
||||||
component: IconExamples,
|
component: IconExamples,
|
||||||
|
decorators: [
|
||||||
|
(Story: StoryObj, context: StoryContext<IconProps>) => (
|
||||||
|
<div class={cx(context.args.inverted || false ? "bg-inv-acc-3" : "")}>
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
@@ -67,6 +75,64 @@ type Story = StoryObj<IconProps>;
|
|||||||
|
|
||||||
export const Default: Story = {};
|
export const Default: Story = {};
|
||||||
|
|
||||||
|
export const Primary: Story = {
|
||||||
|
args: {
|
||||||
|
color: "primary",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Secondary: Story = {
|
||||||
|
args: {
|
||||||
|
color: "secondary",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Tertiary: Story = {
|
||||||
|
args: {
|
||||||
|
color: "tertiary",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Quaternary: Story = {
|
||||||
|
args: {
|
||||||
|
color: "quaternary",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PrimaryInverted: Story = {
|
||||||
|
args: {
|
||||||
|
...Primary.args,
|
||||||
|
inverted: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SecondaryInverted: Story = {
|
||||||
|
args: {
|
||||||
|
...Secondary.args,
|
||||||
|
inverted: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TertiaryInverted: Story = {
|
||||||
|
args: {
|
||||||
|
...Tertiary.args,
|
||||||
|
inverted: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const QuaternaryInverted: Story = {
|
||||||
|
args: {
|
||||||
|
...Quaternary.args,
|
||||||
|
inverted: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Inverted: Story = {
|
||||||
|
args: {
|
||||||
|
inverted: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const Large: Story = {
|
export const Large: Story = {
|
||||||
args: {
|
args: {
|
||||||
width: "2rem",
|
width: "2rem",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import cx from "classnames";
|
import cx from "classnames";
|
||||||
import { Component, JSX, Show, splitProps } from "solid-js";
|
import { Component, JSX, splitProps } from "solid-js";
|
||||||
import ArrowBottom from "@/icons/arrow-bottom.svg";
|
import ArrowBottom from "@/icons/arrow-bottom.svg";
|
||||||
import ArrowLeft from "@/icons/arrow-left.svg";
|
import ArrowLeft from "@/icons/arrow-left.svg";
|
||||||
import ArrowRight from "@/icons/arrow-right.svg";
|
import ArrowRight from "@/icons/arrow-right.svg";
|
||||||
@@ -45,9 +45,10 @@ import Offline from "@/icons/offline.svg";
|
|||||||
import Switch from "@/icons/switch.svg";
|
import Switch from "@/icons/switch.svg";
|
||||||
import Tag from "@/icons/tag.svg";
|
import Tag from "@/icons/tag.svg";
|
||||||
import Machine from "@/icons/machine.svg";
|
import Machine from "@/icons/machine.svg";
|
||||||
import Loader from "@/icons/loader.svg";
|
|
||||||
import { Dynamic } from "solid-js/web";
|
import { Dynamic } from "solid-js/web";
|
||||||
|
|
||||||
|
import { Color, fgClass } from "../colors";
|
||||||
|
|
||||||
const icons = {
|
const icons = {
|
||||||
AI,
|
AI,
|
||||||
ArrowBottom,
|
ArrowBottom,
|
||||||
@@ -98,24 +99,43 @@ const icons = {
|
|||||||
|
|
||||||
export type IconVariant = keyof typeof icons;
|
export type IconVariant = keyof typeof icons;
|
||||||
|
|
||||||
|
const viewBoxes: Partial<Record<IconVariant, string>> = {
|
||||||
|
ClanIcon: "0 0 72 89",
|
||||||
|
Offline: "0 0 38 27",
|
||||||
|
};
|
||||||
|
|
||||||
export interface IconProps extends JSX.SvgSVGAttributes<SVGElement> {
|
export interface IconProps extends JSX.SvgSVGAttributes<SVGElement> {
|
||||||
icon: IconVariant;
|
icon: IconVariant;
|
||||||
class?: string;
|
class?: string;
|
||||||
size?: number | string;
|
size?: number | string;
|
||||||
|
color?: Color;
|
||||||
|
inverted?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Icon: Component<IconProps> = (props) => {
|
const Icon: Component<IconProps> = (props) => {
|
||||||
const [local, iconProps] = splitProps(props, ["icon", "class"]);
|
const [local, iconProps] = splitProps(props, [
|
||||||
|
"icon",
|
||||||
|
"color",
|
||||||
|
"class",
|
||||||
|
"size",
|
||||||
|
"inverted",
|
||||||
|
]);
|
||||||
|
|
||||||
const IconComponent = () => icons[local.icon];
|
const IconComponent = () => icons[local.icon];
|
||||||
|
|
||||||
|
// we need to adjust the view box for certain icons
|
||||||
|
const viewBox = () => viewBoxes[local.icon] ?? "0 0 48 48";
|
||||||
|
|
||||||
return IconComponent() ? (
|
return IconComponent() ? (
|
||||||
<Dynamic
|
<Dynamic
|
||||||
component={IconComponent()}
|
component={IconComponent()}
|
||||||
class={cx("icon", local.class)}
|
class={cx("icon", local.class, fgClass(local.color, local.inverted), {
|
||||||
width={iconProps.size || "1em"}
|
inverted: local.inverted,
|
||||||
height={iconProps.size || "1em"}
|
})}
|
||||||
viewBox="0 0 48 48"
|
data-icon-name={local.icon}
|
||||||
|
width={local.size || "1em"}
|
||||||
|
height={local.size || "1em"}
|
||||||
|
viewBox={viewBox()}
|
||||||
ref={iconProps.ref}
|
ref={iconProps.ref}
|
||||||
{...iconProps}
|
{...iconProps}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
span.tag-status {
|
||||||
|
@apply flex items-center gap-1;
|
||||||
|
|
||||||
|
.indicator {
|
||||||
|
@apply w-1.5 h-1.5 rounded-full m-1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.online > .indicator {
|
||||||
|
background-color: #0ae856; /* todo get from theme */
|
||||||
|
}
|
||||||
|
|
||||||
|
&.offline > .indicator {
|
||||||
|
background-color: #ff2c78; /* todo get from theme */
|
||||||
|
}
|
||||||
|
|
||||||
|
&.installed > .indicator {
|
||||||
|
background-color: var(--clr-fg-inv-3);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import {
|
||||||
|
MachineStatus,
|
||||||
|
TagStatusProps,
|
||||||
|
} from "@/src/components/v2/MachineStatus/MachineStatus";
|
||||||
|
import { Meta, StoryObj } from "@kachurun/storybook-solid";
|
||||||
|
|
||||||
|
const meta: Meta<TagStatusProps> = {
|
||||||
|
title: "Components/MachineStatus",
|
||||||
|
component: MachineStatus,
|
||||||
|
decorators: [
|
||||||
|
(Story: StoryObj) => (
|
||||||
|
<div class="p-5 bg-inv-1">
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<TagStatusProps>;
|
||||||
|
|
||||||
|
export const Online: Story = {
|
||||||
|
args: {
|
||||||
|
status: "Online",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Offline: Story = {
|
||||||
|
args: {
|
||||||
|
status: "Offline",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Installed: Story = {
|
||||||
|
args: {
|
||||||
|
status: "Installed",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NotInstalled: Story = {
|
||||||
|
args: {
|
||||||
|
status: "Not Installed",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const OnlineWithLabel: Story = {
|
||||||
|
args: {
|
||||||
|
...Online.args,
|
||||||
|
label: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const OfflineWithLabel: Story = {
|
||||||
|
args: {
|
||||||
|
...Offline.args,
|
||||||
|
label: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InstalledWithLabel: Story = {
|
||||||
|
args: {
|
||||||
|
...Installed.args,
|
||||||
|
label: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NotInstalledWithLabel: Story = {
|
||||||
|
args: {
|
||||||
|
...NotInstalled.args,
|
||||||
|
label: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import "./MachineStatus.css";
|
||||||
|
|
||||||
|
import { Badge } from "@kobalte/core/badge";
|
||||||
|
import cx from "classnames";
|
||||||
|
import { Show } from "solid-js";
|
||||||
|
import Icon from "../Icon/Icon";
|
||||||
|
import { Typography } from "@/src/components/v2/Typography/Typography";
|
||||||
|
|
||||||
|
export type MachineStatus =
|
||||||
|
| "Online"
|
||||||
|
| "Offline"
|
||||||
|
| "Installed"
|
||||||
|
| "Not Installed";
|
||||||
|
|
||||||
|
export interface TagStatusProps {
|
||||||
|
label?: boolean;
|
||||||
|
status: MachineStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MachineStatus = (props: TagStatusProps) => (
|
||||||
|
<Badge
|
||||||
|
class={cx("tag-status", {
|
||||||
|
online: props.status == "Online",
|
||||||
|
offline: props.status == "Offline",
|
||||||
|
installed: props.status == "Installed",
|
||||||
|
"not-installed": props.status == "Not Installed",
|
||||||
|
})}
|
||||||
|
textValue={props.status}
|
||||||
|
>
|
||||||
|
{props.label && (
|
||||||
|
<Typography hierarchy="label" size="xs" weight="medium" inverted={true}>
|
||||||
|
{props.status}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
<Show
|
||||||
|
when={props.status == "Not Installed"}
|
||||||
|
fallback={<div class="indicator" />}
|
||||||
|
>
|
||||||
|
<Icon icon="Offline" inverted={true} />
|
||||||
|
</Show>
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
10
pkgs/clan-app/ui/src/components/v2/Sidebar/SidebarNav.css
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
div.sidebar {
|
||||||
|
@apply h-full w-auto max-w-60 border-none;
|
||||||
|
|
||||||
|
& > div.header {
|
||||||
|
}
|
||||||
|
|
||||||
|
& > div.body {
|
||||||
|
@apply pt-4 pb-3 px-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
import type { Meta, StoryObj } from "@kachurun/storybook-solid";
|
||||||
|
import {
|
||||||
|
createMemoryHistory,
|
||||||
|
MemoryRouter,
|
||||||
|
Route,
|
||||||
|
RouteSectionProps,
|
||||||
|
} from "@solidjs/router";
|
||||||
|
import {
|
||||||
|
SidebarNav,
|
||||||
|
SidebarNavProps,
|
||||||
|
} from "@/src/components/v2/Sidebar/SidebarNav";
|
||||||
|
import { Suspense } from "solid-js";
|
||||||
|
import { StoryContext } from "@kachurun/storybook-solid-vite";
|
||||||
|
|
||||||
|
const sidebarNavProps: SidebarNavProps = {
|
||||||
|
clanLinks: [
|
||||||
|
{ label: "Brian's Clan", path: "/clan/1" },
|
||||||
|
{ label: "Dave's Clan", path: "/clan/2" },
|
||||||
|
{ label: "Mic92's Clan", path: "/clan/3" },
|
||||||
|
],
|
||||||
|
clanDetail: {
|
||||||
|
label: "Brian's Clan",
|
||||||
|
settingsPath: "/clan/1/settings",
|
||||||
|
machines: [
|
||||||
|
{
|
||||||
|
label: "Backup & Home",
|
||||||
|
path: "/clan/1/machine/backup",
|
||||||
|
serviceCount: 3,
|
||||||
|
status: "Online",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Raspberry Pi",
|
||||||
|
path: "/clan/1/machine/pi",
|
||||||
|
serviceCount: 1,
|
||||||
|
status: "Offline",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Mom's Laptop",
|
||||||
|
path: "/clan/1/machine/moms-laptop",
|
||||||
|
serviceCount: 2,
|
||||||
|
status: "Installed",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Dad's Laptop",
|
||||||
|
path: "/clan/1/machine/dads-laptop",
|
||||||
|
serviceCount: 4,
|
||||||
|
status: "Not Installed",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
extraSections: [
|
||||||
|
{
|
||||||
|
label: "Tools",
|
||||||
|
links: [
|
||||||
|
{ label: "Borgbackup", path: "/clan/1/service/borgbackup" },
|
||||||
|
{ label: "Syncthing", path: "/clan/1/service/syncthing" },
|
||||||
|
{ label: "Mumble", path: "/clan/1/service/mumble" },
|
||||||
|
{ label: "Minecraft", path: "/clan/1/service/minecraft" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Links",
|
||||||
|
links: [
|
||||||
|
{ label: "GitHub", path: "https://github.com/brian-the-dev" },
|
||||||
|
{ label: "Twitter", path: "https://twitter.com/brian_the_dev" },
|
||||||
|
{
|
||||||
|
label: "LinkedIn",
|
||||||
|
path: "https://www.linkedin.com/in/brian-the-dev/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Instagram",
|
||||||
|
path: "https://www.instagram.com/brian_the_dev/",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const meta: Meta<RouteSectionProps> = {
|
||||||
|
title: "Components/Sidebar/Nav",
|
||||||
|
component: SidebarNav,
|
||||||
|
render: (_: never, context: StoryContext<SidebarNavProps>) => {
|
||||||
|
const history = createMemoryHistory();
|
||||||
|
history.set({ value: "/clan/1/machine/backup" });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style="height: 670px;">
|
||||||
|
<MemoryRouter
|
||||||
|
history={history}
|
||||||
|
root={(props) => (
|
||||||
|
<Suspense>
|
||||||
|
<SidebarNav {...sidebarNavProps} />
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Route path="/clan/1/machine/backup" component={(props) => <></>} />
|
||||||
|
</MemoryRouter>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<RouteSectionProps>;
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
args: {},
|
||||||
|
};
|
||||||
47
pkgs/clan-app/ui/src/components/v2/Sidebar/SidebarNav.tsx
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import "./SidebarNav.css";
|
||||||
|
import { SidebarNavHeader } from "@/src/components/v2/Sidebar/SidebarNavHeader";
|
||||||
|
import { SidebarNavBody } from "@/src/components/v2/Sidebar/SidebarNavBody";
|
||||||
|
import { MachineStatus } from "@/src/components/v2/MachineStatus/MachineStatus";
|
||||||
|
|
||||||
|
export interface LinkProps {
|
||||||
|
path: string;
|
||||||
|
label?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SectionProps {
|
||||||
|
label: string;
|
||||||
|
links: LinkProps[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MachineProps {
|
||||||
|
label: string;
|
||||||
|
path: string;
|
||||||
|
status: MachineStatus;
|
||||||
|
serviceCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClanLinkProps {
|
||||||
|
label: string;
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClanProps {
|
||||||
|
label: string;
|
||||||
|
settingsPath: string;
|
||||||
|
machines: MachineProps[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SidebarNavProps {
|
||||||
|
clanDetail: ClanProps;
|
||||||
|
clanLinks: ClanLinkProps[];
|
||||||
|
extraSections: SectionProps[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SidebarNav = (props: SidebarNavProps) => {
|
||||||
|
return (
|
||||||
|
<div class="sidebar">
|
||||||
|
<SidebarNavHeader {...props} />
|
||||||
|
<SidebarNavBody {...props} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
127
pkgs/clan-app/ui/src/components/v2/Sidebar/SidebarNavBody.css
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
div.sidebar-body {
|
||||||
|
@apply py-4 px-2 h-full;
|
||||||
|
@apply border border-inv-3 rounded-bl-md rounded-br-md;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
overflow-y: auto;
|
||||||
|
scrollbar-width: none;
|
||||||
|
|
||||||
|
scrollbar-color: theme(colors.primary.700) theme(colors.primary.600);
|
||||||
|
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
var(--clr-bg-inv-1) 0%,
|
||||||
|
var(--clr-bg-inv-3) 100%
|
||||||
|
);
|
||||||
|
|
||||||
|
@apply backdrop-blur-sm;
|
||||||
|
|
||||||
|
.accordion {
|
||||||
|
@apply w-full mb-4;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
@apply mb-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .item {
|
||||||
|
@apply py-3 px-1.5 bg-inv-3 rounded-md mb-4;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
@apply mb-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .header {
|
||||||
|
@apply flex mb-4 px-2;
|
||||||
|
|
||||||
|
& > .trigger {
|
||||||
|
@apply inline-flex items-center justify-between w-full;
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
@apply z-10;
|
||||||
|
outline: 2px solid hsl(200 98% 39%);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .icon {
|
||||||
|
transition: transform 300ms cubic-bezier(0.87, 0, 0.13, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-expanded] > .icon {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
@apply uppercase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .content {
|
||||||
|
@apply overflow-hidden flex flex-col;
|
||||||
|
animation: slideAccordionUp 300ms cubic-bezier(0.87, 0, 0.13, 1);
|
||||||
|
|
||||||
|
&[data-expanded] {
|
||||||
|
animation: slideAccordionDown 300ms cubic-bezier(0.87, 0, 0.13, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
nav * {
|
||||||
|
@apply outline-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav > a {
|
||||||
|
@apply block w-full px-2 py-1.5 min-h-7 my-2 rounded-md;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
@apply mt-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
@apply mb-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
theme(colors.secondary.900),
|
||||||
|
60%,
|
||||||
|
theme(colors.secondary.600) 100%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
@apply bg-inv-acc-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
@apply bg-inv-acc-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
@apply bg-inv-acc-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideAccordionDown {
|
||||||
|
from {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
height: var(--kb-accordion-content-height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideAccordionUp {
|
||||||
|
from {
|
||||||
|
height: var(--kb-accordion-content-height);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
138
pkgs/clan-app/ui/src/components/v2/Sidebar/SidebarNavBody.tsx
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
import "./SidebarNavBody.css";
|
||||||
|
import { A } from "@solidjs/router";
|
||||||
|
import { Accordion } from "@kobalte/core/accordion";
|
||||||
|
import Icon from "../Icon/Icon";
|
||||||
|
import { Typography } from "@/src/components/v2/Typography/Typography";
|
||||||
|
import {
|
||||||
|
MachineProps,
|
||||||
|
SidebarNavProps,
|
||||||
|
} from "@/src/components/v2/Sidebar/SidebarNav";
|
||||||
|
import { For } from "solid-js";
|
||||||
|
import { MachineStatus } from "@/src/components/v2/MachineStatus/MachineStatus";
|
||||||
|
|
||||||
|
const MachineRoute = (props: MachineProps) => (
|
||||||
|
<div class="flex w-full flex-col gap-2">
|
||||||
|
<div class="flex flex-row items-center justify-between">
|
||||||
|
<Typography
|
||||||
|
hierarchy="label"
|
||||||
|
size="xs"
|
||||||
|
weight="bold"
|
||||||
|
color="primary"
|
||||||
|
inverted={true}
|
||||||
|
>
|
||||||
|
{props.label}
|
||||||
|
</Typography>
|
||||||
|
<MachineStatus status={props.status} />
|
||||||
|
</div>
|
||||||
|
<div class="flex w-full flex-row items-center gap-1">
|
||||||
|
<Icon icon="Flash" size="0.75rem" inverted={true} color="tertiary" />
|
||||||
|
<Typography
|
||||||
|
hierarchy="label"
|
||||||
|
family="mono"
|
||||||
|
size="s"
|
||||||
|
inverted={true}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
{props.serviceCount}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const SidebarNavBody = (props: SidebarNavProps) => {
|
||||||
|
const sectionLabels = props.extraSections.map((section) => section.label);
|
||||||
|
|
||||||
|
// controls which sections are open by default
|
||||||
|
// we want them all to be open by default
|
||||||
|
const defaultAccordionValues = ["your-machines", ...sectionLabels];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="sidebar-body">
|
||||||
|
<Accordion
|
||||||
|
class="accordion"
|
||||||
|
multiple
|
||||||
|
defaultValue={defaultAccordionValues}
|
||||||
|
>
|
||||||
|
<Accordion.Item class="item" value="your-machines">
|
||||||
|
<Accordion.Header class="header">
|
||||||
|
<Accordion.Trigger class="trigger">
|
||||||
|
<Typography
|
||||||
|
class="section-title"
|
||||||
|
hierarchy="label"
|
||||||
|
family="mono"
|
||||||
|
size="xs"
|
||||||
|
inverted={true}
|
||||||
|
color="tertiary"
|
||||||
|
>
|
||||||
|
Your Machines
|
||||||
|
</Typography>
|
||||||
|
<Icon
|
||||||
|
icon="CaretDown"
|
||||||
|
color="tertiary"
|
||||||
|
inverted={true}
|
||||||
|
size="0.75rem"
|
||||||
|
/>
|
||||||
|
</Accordion.Trigger>
|
||||||
|
</Accordion.Header>
|
||||||
|
<Accordion.Content class="content">
|
||||||
|
<nav>
|
||||||
|
<For each={props.clanDetail.machines}>
|
||||||
|
{(machine) => (
|
||||||
|
<A href={machine.path}>
|
||||||
|
<MachineRoute {...machine} />
|
||||||
|
</A>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</nav>
|
||||||
|
</Accordion.Content>
|
||||||
|
</Accordion.Item>
|
||||||
|
|
||||||
|
<For each={props.extraSections}>
|
||||||
|
{(section) => (
|
||||||
|
<Accordion.Item class="item" value={section.label}>
|
||||||
|
<Accordion.Header class="header">
|
||||||
|
<Accordion.Trigger class="trigger">
|
||||||
|
<Typography
|
||||||
|
class="section-title"
|
||||||
|
hierarchy="label"
|
||||||
|
family="mono"
|
||||||
|
size="xs"
|
||||||
|
inverted={true}
|
||||||
|
color="tertiary"
|
||||||
|
>
|
||||||
|
{section.label}
|
||||||
|
</Typography>
|
||||||
|
<Icon
|
||||||
|
icon="CaretDown"
|
||||||
|
color="tertiary"
|
||||||
|
inverted={true}
|
||||||
|
size="0.75rem"
|
||||||
|
/>
|
||||||
|
</Accordion.Trigger>
|
||||||
|
</Accordion.Header>
|
||||||
|
<Accordion.Content class="content">
|
||||||
|
<nav>
|
||||||
|
<For each={section.links || []}>
|
||||||
|
{(link) => (
|
||||||
|
<A href={link.path}>
|
||||||
|
<Typography
|
||||||
|
hierarchy="body"
|
||||||
|
size="xs"
|
||||||
|
weight="bold"
|
||||||
|
color="primary"
|
||||||
|
inverted={true}
|
||||||
|
>
|
||||||
|
{link.label}
|
||||||
|
</Typography>
|
||||||
|
</A>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</nav>
|
||||||
|
</Accordion.Content>
|
||||||
|
</Accordion.Item>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</Accordion>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
div.sidebar-header {
|
||||||
|
@apply flex items-center justify-center w-full px-1 py-1;
|
||||||
|
@apply border border-inv-3 rounded-md rounded-bl-none rounded-br-none;
|
||||||
|
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
var(--clr-bg-inv-3) 0%,
|
||||||
|
var(--clr-bg-inv-4) 100%
|
||||||
|
);
|
||||||
|
|
||||||
|
& > .dropdown-trigger {
|
||||||
|
@apply flex items-center justify-between flex-grow px-1 py-1;
|
||||||
|
@apply rounded-tl-md rounded-tr-md;
|
||||||
|
@apply border border-transparent border-b-0;
|
||||||
|
|
||||||
|
transition: all 250ms ease-in-out;
|
||||||
|
|
||||||
|
div.title {
|
||||||
|
@apply flex items-center gap-2 justify-start;
|
||||||
|
|
||||||
|
& > .clan-icon {
|
||||||
|
@apply rounded-full bg-inv-4 w-7 h-7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon[data-icon-name="CaretDown"] {
|
||||||
|
transition: transform 300ms cubic-bezier(0.87, 0, 0.13, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-expanded] {
|
||||||
|
@apply bg-def-1 border-def-2;
|
||||||
|
|
||||||
|
.icon[data-icon-name="CaretDown"] {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-dropdown-content {
|
||||||
|
@apply flex flex-col w-full px-2 py-1.5;
|
||||||
|
@apply bg-def-1 rounded-bl-md rounded-br-md;
|
||||||
|
@apply border border-def-2;
|
||||||
|
|
||||||
|
animation: sidebarNavContentHide 250ms ease-in forwards;
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
@apply flex items-center justify-start w-full px-1.5 py-2 gap-2 rounded;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
@apply bg-def-acc-2 cursor-pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-group {
|
||||||
|
@apply flex flex-col gap-2;
|
||||||
|
@apply px-1;
|
||||||
|
|
||||||
|
.dropdown-group-label {
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-group-items {
|
||||||
|
@apply rounded px-1 py-1.5 bg-def-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-dropdown-content[data-expanded] {
|
||||||
|
animation: sidebarNavContentShow 250ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes sidebarNavContentShow {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.96);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes sidebarNavContentHide {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.96);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import "./SidebarNavHeader.css";
|
||||||
|
import Icon from "@/src/components/v2/Icon/Icon";
|
||||||
|
import { DropdownMenu } from "@kobalte/core/dropdown-menu";
|
||||||
|
import { useNavigate } from "@solidjs/router";
|
||||||
|
import { Typography } from "../Typography/Typography";
|
||||||
|
import { createSignal, For } from "solid-js";
|
||||||
|
import {
|
||||||
|
ClanLinkProps,
|
||||||
|
ClanProps,
|
||||||
|
} from "@/src/components/v2/Sidebar/SidebarNav";
|
||||||
|
|
||||||
|
export interface SidebarHeaderProps {
|
||||||
|
clanDetail: ClanProps;
|
||||||
|
clanLinks: ClanLinkProps[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SidebarNavHeader = (props: SidebarHeaderProps) => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const [open, setOpen] = createSignal(false);
|
||||||
|
|
||||||
|
const firstChar = props.clanDetail.label.charAt(0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<DropdownMenu open={open()} onOpenChange={setOpen} sameWidth={true}>
|
||||||
|
<DropdownMenu.Trigger class="dropdown-trigger">
|
||||||
|
<div class="title">
|
||||||
|
<div class="clan-icon">
|
||||||
|
<Typography
|
||||||
|
hierarchy="label"
|
||||||
|
size="s"
|
||||||
|
weight="bold"
|
||||||
|
inverted={true}
|
||||||
|
>
|
||||||
|
{firstChar.toUpperCase()}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<Typography
|
||||||
|
hierarchy="label"
|
||||||
|
size="s"
|
||||||
|
weight="bold"
|
||||||
|
inverted={!open()}
|
||||||
|
>
|
||||||
|
{props.clanDetail.label}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<DropdownMenu.Icon>
|
||||||
|
<Icon icon={"CaretDown"} inverted={!open()} size="0.75rem" />
|
||||||
|
</DropdownMenu.Icon>
|
||||||
|
</DropdownMenu.Trigger>
|
||||||
|
<DropdownMenu.Portal>
|
||||||
|
<DropdownMenu.Content class="sidebar-dropdown-content">
|
||||||
|
<DropdownMenu.Item
|
||||||
|
class="dropdown-item"
|
||||||
|
onSelect={() => navigate(props.clanDetail.settingsPath)}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
icon="Settings"
|
||||||
|
size="0.75rem"
|
||||||
|
inverted={true}
|
||||||
|
color="tertiary"
|
||||||
|
/>
|
||||||
|
<Typography hierarchy="label" size="xs" weight="medium">
|
||||||
|
Settings
|
||||||
|
</Typography>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
<DropdownMenu.Group class="dropdown-group">
|
||||||
|
<DropdownMenu.GroupLabel class="dropdown-group-label">
|
||||||
|
<Typography
|
||||||
|
hierarchy="label"
|
||||||
|
family="mono"
|
||||||
|
size="xs"
|
||||||
|
color="tertiary"
|
||||||
|
>
|
||||||
|
YOUR CLANS
|
||||||
|
</Typography>
|
||||||
|
</DropdownMenu.GroupLabel>
|
||||||
|
<div class="dropdown-group-items">
|
||||||
|
<For each={props.clanLinks}>
|
||||||
|
{(clan) => (
|
||||||
|
<DropdownMenu.Item
|
||||||
|
class="dropdown-item"
|
||||||
|
onSelect={() => navigate(clan.path)}
|
||||||
|
>
|
||||||
|
<Typography hierarchy="label" size="xs" weight="medium">
|
||||||
|
{clan.label}
|
||||||
|
</Typography>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</DropdownMenu.Group>
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu.Portal>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,151 +1,151 @@
|
|||||||
/* Body */
|
/* Body */
|
||||||
.typography {
|
.typography {
|
||||||
&.font-weight-normal {
|
&.weight-normal {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-weight-medium {
|
&.weight-medium {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-weight-bold {
|
&.weight-bold {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-body {
|
&.body {
|
||||||
&.font-family-regular {
|
&.family-regular {
|
||||||
font-family: "Archivo", sans-serif;
|
font-family: "Archivo", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-family-condensed {
|
&.family-condensed {
|
||||||
font-family: "Archivo SemiCondensed", sans-serif;
|
font-family: "Archivo SemiCondensed", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-default {
|
&.size-default {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
line-height: 1.32;
|
line-height: 1.32;
|
||||||
letter-spacing: 0.02rem;
|
letter-spacing: 0.02rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-s {
|
&.size-s {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.32;
|
line-height: 1.32;
|
||||||
letter-spacing: 0.0175rem;
|
letter-spacing: 0.0175rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-xs {
|
&.size-xs {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
line-height: 1.32;
|
line-height: 1.32;
|
||||||
letter-spacing: 0.0225rem;
|
letter-spacing: 0.0225rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-xxs {
|
&.size-xxs {
|
||||||
font-size: 0.6875rem;
|
font-size: 0.6875rem;
|
||||||
line-height: 1.32;
|
line-height: 1.32;
|
||||||
letter-spacing: 0.00688rem;
|
letter-spacing: 0.00688rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-label {
|
&.label {
|
||||||
&.font-family-condensed {
|
&.family-condensed {
|
||||||
font-family: "Archivo SemiCondensed", sans-serif;
|
font-family: "Archivo SemiCondensed", sans-serif;
|
||||||
|
|
||||||
&.font-size-default {
|
&.size-default {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.32;
|
line-height: 1;
|
||||||
letter-spacing: 0.0175rem;
|
letter-spacing: 0.0175rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-s {
|
&.size-s {
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
line-height: 1.32;
|
line-height: 1;
|
||||||
letter-spacing: 0.0175rem;
|
letter-spacing: 0.0175rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-xs {
|
&.size-xs {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
line-height: 1.32;
|
line-height: 1;
|
||||||
letter-spacing: 0.0075rem;
|
letter-spacing: 0.0075rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-family-mono {
|
&.family-mono {
|
||||||
font-family: "Commit Mono", monospace;
|
font-family: "Commit Mono", monospace;
|
||||||
|
|
||||||
&.font-size-default {
|
&.size-default {
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
line-height: 0;
|
line-height: 1;
|
||||||
letter-spacing: normal;
|
letter-spacing: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-s {
|
&.size-s {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
line-height: 0;
|
line-height: 1;
|
||||||
letter-spacing: normal;
|
letter-spacing: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-xs {
|
&.size-xs {
|
||||||
font-size: 0.6875rem;
|
font-size: 0.6875rem;
|
||||||
line-height: 0;
|
line-height: 1;
|
||||||
letter-spacing: normal;
|
letter-spacing: normal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-title {
|
&.title {
|
||||||
&.font-family-regular {
|
&.family-regular {
|
||||||
font-family: "Archivo", sans-serif;
|
font-family: "Archivo", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-default {
|
&.size-default {
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
line-height: 124%;
|
line-height: 124%;
|
||||||
letter-spacing: 0.03375rem;
|
letter-spacing: 0.03375rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-m {
|
&.size-m {
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
line-height: 124%;
|
line-height: 124%;
|
||||||
letter-spacing: 0.0375rem;
|
letter-spacing: 0.0375rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-l {
|
&.size-l {
|
||||||
font-size: 1.375rem;
|
font-size: 1.375rem;
|
||||||
line-height: 124%;
|
line-height: 124%;
|
||||||
letter-spacing: 0.04125rem;
|
letter-spacing: 0.04125rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-headline {
|
&.headline {
|
||||||
&.font-family-regular {
|
&.family-regular {
|
||||||
font-family: "Archivo", sans-serif;
|
font-family: "Archivo", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-default {
|
&.size-default {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
line-height: 116%;
|
line-height: 116%;
|
||||||
letter-spacing: 0.015rem;
|
letter-spacing: 0.015rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-m {
|
&.size-m {
|
||||||
font-size: 1.75rem;
|
font-size: 1.75rem;
|
||||||
line-height: 116%;
|
line-height: 116%;
|
||||||
letter-spacing: 0.0175rem;
|
letter-spacing: 0.0175rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-l {
|
&.size-l {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
line-height: 116%;
|
line-height: 116%;
|
||||||
letter-spacing: 0.06rem;
|
letter-spacing: 0.06rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-teaser {
|
&.teaser {
|
||||||
&.font-family-regular {
|
&.family-regular {
|
||||||
font-family: "Archivo", sans-serif;
|
font-family: "Archivo", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.font-size-default {
|
&.size-default {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
letter-spacing: -0.06rem;
|
letter-spacing: -0.06rem;
|
||||||
|
|||||||
@@ -14,9 +14,7 @@ There are two fonts being used within our typography system:
|
|||||||
## UI Components
|
## UI Components
|
||||||
|
|
||||||
When creating UI components that a user will interact with,
|
When creating UI components that a user will interact with,
|
||||||
you must use the condensed form of `Body`, `Label` and `Label Mono`.
|
you **must use** `Label` or `Label Mono`.
|
||||||
|
|
||||||
<DocsStory of={TypographyStories.BodyCondensed} />
|
|
||||||
|
|
||||||
<DocsStory of={TypographyStories.LabelCondensed} />
|
<DocsStory of={TypographyStories.LabelCondensed} />
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
import type { Meta, StoryObj } from "@kachurun/storybook-solid";
|
import type { Meta, StoryObj } from "@kachurun/storybook-solid";
|
||||||
|
|
||||||
import {
|
import { Family, Hierarchy, Typography, Weight } from "./Typography";
|
||||||
AllowedSizes,
|
|
||||||
Color,
|
|
||||||
Family,
|
|
||||||
Hierarchy,
|
|
||||||
Typography,
|
|
||||||
Weight,
|
|
||||||
} from "./Typography";
|
|
||||||
import { Component, For, Show } from "solid-js";
|
import { Component, For, Show } from "solid-js";
|
||||||
|
import { AllColors } from "@/src/components/v2/colors";
|
||||||
|
|
||||||
interface TypographyExamplesProps {
|
interface TypographyExamplesProps {
|
||||||
weights: Weight[];
|
weights: Weight[];
|
||||||
@@ -19,14 +13,6 @@ interface TypographyExamplesProps {
|
|||||||
inverted?: boolean;
|
inverted?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const colors: (Color | "inherit")[] = [
|
|
||||||
"inherit",
|
|
||||||
"primary",
|
|
||||||
"secondary",
|
|
||||||
"tertiary",
|
|
||||||
"quaternary",
|
|
||||||
];
|
|
||||||
|
|
||||||
const TypographyExamples: Component<TypographyExamplesProps> = (props) => (
|
const TypographyExamples: Component<TypographyExamplesProps> = (props) => (
|
||||||
<table
|
<table
|
||||||
class="w-full min-w-max table-auto text-left"
|
class="w-full min-w-max table-auto text-left"
|
||||||
@@ -59,7 +45,7 @@ const TypographyExamples: Component<TypographyExamplesProps> = (props) => (
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={props.colors}>
|
<Show when={props.colors}>
|
||||||
<For each={colors}>
|
<For each={AllColors}>
|
||||||
{(color) => (
|
{(color) => (
|
||||||
<>
|
<>
|
||||||
<Typography
|
<Typography
|
||||||
|
|||||||
@@ -1,36 +1,14 @@
|
|||||||
import { type JSX, mergeProps } from "solid-js";
|
import { type JSX } from "solid-js";
|
||||||
import { Dynamic } from "solid-js/web";
|
import { Dynamic } from "solid-js/web";
|
||||||
import cx from "classnames";
|
import cx from "classnames";
|
||||||
import "./Typography.css";
|
import "./Typography.css";
|
||||||
|
import { Color, fgClass } from "@/src/components/v2/colors";
|
||||||
|
|
||||||
export type Tag = "span" | "p" | "h1" | "h2" | "h3" | "h4" | "div";
|
export type Tag = "span" | "p" | "h1" | "h2" | "h3" | "h4" | "div";
|
||||||
export type Color = "primary" | "secondary" | "tertiary" | "quaternary";
|
|
||||||
export type Hierarchy = "body" | "title" | "headline" | "label" | "teaser";
|
export type Hierarchy = "body" | "title" | "headline" | "label" | "teaser";
|
||||||
export type Weight = "normal" | "medium" | "bold";
|
export type Weight = "normal" | "medium" | "bold";
|
||||||
export type Family = "regular" | "condensed" | "mono";
|
export type Family = "regular" | "condensed" | "mono";
|
||||||
|
|
||||||
const colorMap: Record<Color, string> = {
|
|
||||||
primary: cx("fg-def-1"),
|
|
||||||
secondary: cx("fg-def-2"),
|
|
||||||
tertiary: cx("fg-def-3"),
|
|
||||||
quaternary: cx("fg-def-4"),
|
|
||||||
};
|
|
||||||
|
|
||||||
const invertedColorMap: Record<Color, string> = {
|
|
||||||
primary: cx("fg-inv-1"),
|
|
||||||
secondary: cx("fg-inv-2"),
|
|
||||||
tertiary: cx("fg-inv-3"),
|
|
||||||
quaternary: cx("fg-inv-4"),
|
|
||||||
};
|
|
||||||
|
|
||||||
const colorFor = (color: Color | "inherit" = "primary", inverted = false) => {
|
|
||||||
if (color === "inherit") {
|
|
||||||
return "text-inherit";
|
|
||||||
}
|
|
||||||
|
|
||||||
return inverted ? invertedColorMap[color] : colorMap[color];
|
|
||||||
};
|
|
||||||
|
|
||||||
// type Size = "default" | "xs" | "s" | "m" | "l";
|
// type Size = "default" | "xs" | "s" | "m" | "l";
|
||||||
interface SizeForHierarchy {
|
interface SizeForHierarchy {
|
||||||
body: {
|
body: {
|
||||||
@@ -63,30 +41,30 @@ export type AllowedSizes<H extends Hierarchy> = keyof SizeForHierarchy[H];
|
|||||||
|
|
||||||
const sizeHierarchyMap: SizeForHierarchy = {
|
const sizeHierarchyMap: SizeForHierarchy = {
|
||||||
body: {
|
body: {
|
||||||
default: cx("font-size-default"),
|
default: cx("size-default"),
|
||||||
s: cx("font-size-s"),
|
s: cx("size-s"),
|
||||||
xs: cx("font-size-xs"),
|
xs: cx("size-xs"),
|
||||||
xxs: cx("font-size-xxs"),
|
xxs: cx("size-xxs"),
|
||||||
},
|
},
|
||||||
headline: {
|
headline: {
|
||||||
default: cx("font-size-default"),
|
default: cx("size-default"),
|
||||||
m: cx("font-size-m"),
|
m: cx("size-m"),
|
||||||
l: cx("font-size-l"),
|
l: cx("size-l"),
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
default: cx("font-size-default"),
|
default: cx("size-default"),
|
||||||
// xs: cx("font-size-xs"),
|
// xs: cx("size-xs"),
|
||||||
// s: cx("font-size-s"),
|
// s: cx("size-s"),
|
||||||
m: cx("font-size-m"),
|
m: cx("size-m"),
|
||||||
l: cx("font-size-l"),
|
l: cx("size-l"),
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
default: cx("font-size-default"),
|
default: cx("size-default"),
|
||||||
s: cx("font-size-s"),
|
s: cx("size-s"),
|
||||||
xs: cx("font-size-xs"),
|
xs: cx("size-xs"),
|
||||||
},
|
},
|
||||||
teaser: {
|
teaser: {
|
||||||
default: cx("font-size-default"),
|
default: cx("size-default"),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -99,50 +77,43 @@ const defaultFamilyMap: Record<Hierarchy, Family> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const weightMap: Record<Weight, string> = {
|
const weightMap: Record<Weight, string> = {
|
||||||
normal: cx("font-weight-normal"),
|
normal: cx("weight-normal"),
|
||||||
medium: cx("font-weight-medium"),
|
medium: cx("weight-medium"),
|
||||||
bold: cx("font-weight-bold"),
|
bold: cx("weight-bold"),
|
||||||
};
|
};
|
||||||
|
|
||||||
interface _TypographyProps<H extends Hierarchy> {
|
interface _TypographyProps<H extends Hierarchy> {
|
||||||
hierarchy: H;
|
hierarchy: H;
|
||||||
size: AllowedSizes<H>;
|
size: AllowedSizes<H>;
|
||||||
color?: Color | "inherit";
|
color?: Color;
|
||||||
children: JSX.Element;
|
children: JSX.Element;
|
||||||
weight?: Weight;
|
weight?: Weight;
|
||||||
family?: Family;
|
family?: Family;
|
||||||
inverted?: boolean;
|
inverted?: boolean;
|
||||||
tag?: Tag;
|
tag?: Tag;
|
||||||
class?: string;
|
class?: string;
|
||||||
classList?: Record<string, boolean>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Typography = <H extends Hierarchy>(props: _TypographyProps<H>) => {
|
export const Typography = <H extends Hierarchy>(props: _TypographyProps<H>) => {
|
||||||
const family = () =>
|
const family = () =>
|
||||||
`font-family-${props.family || defaultFamilyMap[props.hierarchy]}`;
|
`family-${props.family || defaultFamilyMap[props.hierarchy]}`;
|
||||||
|
const hierarchy = () => props.hierarchy || "body";
|
||||||
const color = () => colorFor(props.color, props.inverted);
|
const size = () => sizeHierarchyMap[props.hierarchy][props.size] as string;
|
||||||
|
const weight = () => weightMap[props.weight || "normal"];
|
||||||
const classList = mergeProps(props.classList, {
|
const color = () => fgClass(props.color, props.inverted);
|
||||||
"font-body": props.hierarchy === "body" || !props.hierarchy,
|
|
||||||
"font-label": props.hierarchy === "label",
|
|
||||||
"font-title": props.hierarchy === "title",
|
|
||||||
"font-headline": props.hierarchy === "headline",
|
|
||||||
"font-teaser": props.hierarchy === "teaser",
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dynamic
|
<Dynamic
|
||||||
class={cx(
|
class={cx(
|
||||||
"typography",
|
"typography",
|
||||||
color(),
|
hierarchy(),
|
||||||
family(),
|
family(),
|
||||||
weightMap[props.weight || "normal"],
|
weight(),
|
||||||
sizeHierarchyMap[props.hierarchy][props.size] as string,
|
size(),
|
||||||
|
color(),
|
||||||
props.class,
|
props.class,
|
||||||
)}
|
)}
|
||||||
component={props.tag || "span"}
|
component={props.tag || "span"}
|
||||||
classList={classList}
|
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</Dynamic>
|
</Dynamic>
|
||||||
|
|||||||
41
pkgs/clan-app/ui/src/components/v2/colors.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
export type Color =
|
||||||
|
| "primary"
|
||||||
|
| "secondary"
|
||||||
|
| "tertiary"
|
||||||
|
| "quaternary"
|
||||||
|
| "inherit";
|
||||||
|
|
||||||
|
export const AllColors: Color[] = [
|
||||||
|
"primary",
|
||||||
|
"secondary",
|
||||||
|
"tertiary",
|
||||||
|
"quaternary",
|
||||||
|
"inherit",
|
||||||
|
];
|
||||||
|
|
||||||
|
const colorMap: Record<Color, string> = {
|
||||||
|
primary: "fg-def-1",
|
||||||
|
secondary: "fg-def-2",
|
||||||
|
tertiary: "fg-def-3",
|
||||||
|
quaternary: "fg-def-4",
|
||||||
|
inherit: "text-inherit",
|
||||||
|
};
|
||||||
|
|
||||||
|
const invertedColorMap: Record<Color, string> = {
|
||||||
|
primary: "fg-inv-1",
|
||||||
|
secondary: "fg-inv-2",
|
||||||
|
tertiary: "fg-inv-3",
|
||||||
|
quaternary: "fg-inv-4",
|
||||||
|
inherit: "text-inherit",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fgClass = (
|
||||||
|
color: Color | "inherit" = "primary",
|
||||||
|
inverted = false,
|
||||||
|
) => {
|
||||||
|
if (color === "inherit") {
|
||||||
|
return "text-inherit";
|
||||||
|
}
|
||||||
|
|
||||||
|
return inverted ? invertedColorMap[color] : colorMap[color];
|
||||||
|
};
|
||||||
@@ -102,3 +102,13 @@ html {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
/* Standard */
|
/* Standard */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.no-scrollbar {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import typography from "@tailwindcss/typography";
|
|
||||||
import kobalte from "@kobalte/tailwindcss";
|
import kobalte from "@kobalte/tailwindcss";
|
||||||
import core from "./tailwind/core-plugin";
|
import core from "./tailwind/core-plugin";
|
||||||
|
|
||||||
@@ -6,7 +5,7 @@ import core from "./tailwind/core-plugin";
|
|||||||
const config = {
|
const config = {
|
||||||
content: ["./src/**/*.{js,jsx,ts,tsx}"],
|
content: ["./src/**/*.{js,jsx,ts,tsx}"],
|
||||||
theme: {},
|
theme: {},
|
||||||
plugins: [typography, core, kobalte],
|
plugins: [core, kobalte],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import plugin from "tailwindcss/plugin";
|
import plugin from "tailwindcss/plugin";
|
||||||
import { typography } from "./typography";
|
|
||||||
// @ts-expect-error: lib of tailwind has no types
|
// @ts-expect-error: lib of tailwind has no types
|
||||||
import { parseColor } from "tailwindcss/lib/util/color";
|
import { parseColor } from "tailwindcss/lib/util/color";
|
||||||
|
|
||||||
@@ -154,7 +153,7 @@ export default plugin.withOptions(
|
|||||||
backgroundColor: theme("colors.secondary.700"),
|
backgroundColor: theme("colors.secondary.700"),
|
||||||
},
|
},
|
||||||
".bg-inv-acc-4": {
|
".bg-inv-acc-4": {
|
||||||
backgroundColor: theme("colors.secondary.900"),
|
backgroundColor: theme("colors.primary.950"),
|
||||||
},
|
},
|
||||||
|
|
||||||
// bg inverse accent
|
// bg inverse accent
|
||||||
@@ -252,7 +251,7 @@ export default plugin.withOptions(
|
|||||||
500: toRGB("#526f6f"),
|
500: toRGB("#526f6f"),
|
||||||
600: toRGB("#4b6767"),
|
600: toRGB("#4b6767"),
|
||||||
700: toRGB("#345253"),
|
700: toRGB("#345253"),
|
||||||
800: toRGB("#2b4647"),
|
800: toRGB("#2e4a4b"),
|
||||||
900: toRGB("#203637"),
|
900: toRGB("#203637"),
|
||||||
950: toRGB("#162324"),
|
950: toRGB("#162324"),
|
||||||
},
|
},
|
||||||
@@ -316,7 +315,6 @@ export default plugin.withOptions(
|
|||||||
"0px 0px 0px 1px white, 0px 0px 0px 2px var(--clr-bg-inv-acc-4, #203637), 2px 2px 0px 0px var(--clr-bg-inv-acc-2, #4F747A) inset",
|
"0px 0px 0px 1px white, 0px 0px 0px 2px var(--clr-bg-inv-acc-4, #203637), 2px 2px 0px 0px var(--clr-bg-inv-acc-2, #4F747A) inset",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
...typography,
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
import defaultTheme from "tailwindcss/defaultTheme";
|
|
||||||
import type { Config } from "tailwindcss";
|
|
||||||
|
|
||||||
export const typography: Partial<Config["theme"]> = {
|
|
||||||
fontFamily: {
|
|
||||||
sans: ["Archivo SemiCondensed", ...defaultTheme.fontFamily.sans],
|
|
||||||
},
|
|
||||||
fontSize: {
|
|
||||||
...defaultTheme.fontSize,
|
|
||||||
title: ["1.125rem", { lineHeight: "124%" }],
|
|
||||||
"title-m": ["1.25rem", { lineHeight: "124%" }],
|
|
||||||
"title-l": ["1.375rem", { lineHeight: "124%" }],
|
|
||||||
label: ["0.8125rem", { lineHeight: "100%" }],
|
|
||||||
"label-s": ["0.75rem", { lineHeight: "100%" }],
|
|
||||||
"label-xs": ["0.6875rem", { lineHeight: "124%" }],
|
|
||||||
},
|
|
||||||
// textColor: {
|
|
||||||
// ...defaultTheme.textColor,
|
|
||||||
// primary: "#0D1416",
|
|
||||||
// secondary: "#2C4347",
|
|
||||||
// },
|
|
||||||
} as const;
|
|
||||||