@spree/dashboard-ui 6.0.0 → 6.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -6
- package/src/index.ts +2 -0
- package/src/shadcn.css +640 -0
- package/src/spree/browser-icon.tsx +36 -0
- package/src/spree/collapsible-card.tsx +66 -0
- package/src/spree/icons.ts +3 -0
- package/src/spree/metadata/metadata-card.tsx +140 -35
- package/src/spree/step-icon.tsx +74 -0
- package/src/styles.css +3 -3
- package/src/ui/badge.tsx +3 -0
- package/src/ui/command.tsx +134 -35
- package/src/ui/dropdown-menu.tsx +7 -3
- package/src/ui/field.tsx +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { cn } from '../lib/utils'
|
|
2
|
+
|
|
3
|
+
/** A browser with a logo in `BrowserIcon`. */
|
|
4
|
+
export type BrowserName = 'chrome' | 'firefox' | 'opera' | 'safari'
|
|
5
|
+
|
|
6
|
+
// Path data from Simple Icons (https://simpleicons.org, CC0), copied rather
|
|
7
|
+
// than depended on: the package is a single 5 MB module. Microsoft's logos,
|
|
8
|
+
// Edge's among them, are no longer in Simple Icons.
|
|
9
|
+
const LOGOS: Record<BrowserName, { color: string; path: string }> = {
|
|
10
|
+
chrome: {
|
|
11
|
+
color: '#4285F4',
|
|
12
|
+
path: 'M12 0C8.21 0 4.831 1.757 2.632 4.501l3.953 6.848A5.454 5.454 0 0 1 12 6.545h10.691A12 12 0 0 0 12 0zM1.931 5.47A11.943 11.943 0 0 0 0 12c0 6.012 4.42 10.991 10.189 11.864l3.953-6.847a5.45 5.45 0 0 1-6.865-2.29zm13.342 2.166a5.446 5.446 0 0 1 1.45 7.09l.002.001h-.002l-5.344 9.257c.206.01.413.016.621.016 6.627 0 12-5.373 12-12 0-1.54-.29-3.011-.818-4.364zM12 16.364a4.364 4.364 0 1 1 0-8.728 4.364 4.364 0 0 1 0 8.728Z',
|
|
13
|
+
},
|
|
14
|
+
firefox: {
|
|
15
|
+
color: '#FF7139',
|
|
16
|
+
path: 'M8.824 7.287c.008 0 .004 0 0 0zm-2.8-1.4c.006 0 .003 0 0 0zm16.754 2.161c-.505-1.215-1.53-2.528-2.333-2.943.654 1.283 1.033 2.57 1.177 3.53l.002.02c-1.314-3.278-3.544-4.6-5.366-7.477-.091-.147-.184-.292-.273-.446a3.545 3.545 0 01-.13-.24 2.118 2.118 0 01-.172-.46.03.03 0 00-.027-.03.038.038 0 00-.021 0l-.006.001a.037.037 0 00-.01.005L15.624 0c-2.585 1.515-3.657 4.168-3.932 5.856a6.197 6.197 0 00-2.305.587.297.297 0 00-.147.37c.057.162.24.24.396.17a5.622 5.622 0 012.008-.523l.067-.005a5.847 5.847 0 011.957.222l.095.03a5.816 5.816 0 01.616.228c.08.036.16.073.238.112l.107.055a5.835 5.835 0 01.368.211 5.953 5.953 0 012.034 2.104c-.62-.437-1.733-.868-2.803-.681 4.183 2.09 3.06 9.292-2.737 9.02a5.164 5.164 0 01-1.513-.292 4.42 4.42 0 01-.538-.232c-1.42-.735-2.593-2.121-2.74-3.806 0 0 .537-2 3.845-2 .357 0 1.38-.998 1.398-1.287-.005-.095-2.029-.9-2.817-1.677-.422-.416-.622-.616-.8-.767a3.47 3.47 0 00-.301-.227 5.388 5.388 0 01-.032-2.842c-1.195.544-2.124 1.403-2.8 2.163h-.006c-.46-.584-.428-2.51-.402-2.913-.006-.025-.343.176-.389.206-.406.29-.787.616-1.136.974-.397.403-.76.839-1.085 1.303a9.816 9.816 0 00-1.562 3.52c-.003.013-.11.487-.19 1.073-.013.09-.026.181-.037.272a7.8 7.8 0 00-.069.667l-.002.034-.023.387-.001.06C.386 18.795 5.593 24 12.016 24c5.752 0 10.527-4.176 11.463-9.661.02-.149.035-.298.052-.448.232-1.994-.025-4.09-.753-5.844z',
|
|
17
|
+
},
|
|
18
|
+
opera: {
|
|
19
|
+
color: '#FF1B2D',
|
|
20
|
+
path: 'M8.051 5.238c-1.328 1.566-2.186 3.883-2.246 6.48v.564c.061 2.598.918 4.912 2.246 6.479 1.721 2.236 4.279 3.654 7.139 3.654 1.756 0 3.4-.537 4.807-1.471C17.879 22.846 15.074 24 12 24c-.192 0-.383-.004-.57-.014C5.064 23.689 0 18.436 0 12 0 5.371 5.373 0 12 0h.045c3.055.012 5.84 1.166 7.953 3.055-1.408-.93-3.051-1.471-4.81-1.471-2.858 0-5.417 1.42-7.14 3.654h.003zM24 12c0 3.556-1.545 6.748-4.002 8.945-3.078 1.5-5.946.451-6.896-.205 3.023-.664 5.307-4.32 5.307-8.74 0-4.422-2.283-8.075-5.307-8.74.949-.654 3.818-1.703 6.896-.205C22.455 5.25 24 8.445 24 12z',
|
|
21
|
+
},
|
|
22
|
+
safari: {
|
|
23
|
+
color: '#006CFF',
|
|
24
|
+
path: 'M12 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0zm-.004.953h.006c.063 0 .113.05.113.113v1.842c0 .063-.05.113-.113.113h-.006a.112.112 0 0 1-.113-.113V1.066c0-.063.05-.113.113-.113zm-.941.041c.056.001.104.046.11.104l.077.918a.112.112 0 0 1-.101.12h-.01a.11.11 0 0 1-.12-.1l-.08-.919a.112.112 0 0 1 .102-.12h.01l.012-.003zm1.892 0H12.965a.113.113 0 0 1 .103.121l-.08.92a.111.111 0 0 1-.12.102h-.009a.111.111 0 0 1-.101-.121l.078-.92a.112.112 0 0 1 .111-.102zm-2.838.123a.11.11 0 0 1 .106.092l.32 1.818c.01.06-.03.119-.09.13l-.01.001a.111.111 0 0 1-.128-.09l-.32-1.818a.111.111 0 0 1 .09-.129l.01-.002a.103.103 0 0 1 .022-.002zm3.784.002h.021l.008.002c.061.01.102.07.092.131l-.32 1.814c-.011.062-.07.101-.132.09h-.005a.113.113 0 0 1-.092-.13l.32-1.815a.111.111 0 0 1 .108-.092zm-4.715.203c.048.002.09.035.103.084l.239.893a.112.112 0 0 1-.079.139l-.005.001a.114.114 0 0 1-.14-.08l-.237-.894a.11.11 0 0 1 .078-.137l.006-.002a.123.123 0 0 1 .035-.004zm5.644 0a.11.11 0 0 1 .033.004l.006.002c.06.016.097.079.08.139l-.24.892a.112.112 0 0 1-.137.08l-.005-.002a.114.114 0 0 1-.08-.138l.24-.893a.112.112 0 0 1 .103-.084zm-6.562.285a.11.11 0 0 1 .107.073L9 3.42a.107.107 0 0 1-.064.139l-.012.005a.11.11 0 0 1-.14-.066L8.15 1.76a.11.11 0 0 1 .065-.14l.014-.005a.106.106 0 0 1 .03-.008zm7.469.002c.014 0 .028.001.042.006l.012.006c.057.02.087.082.067.139l-.633 1.738a.11.11 0 0 1-.14.066l-.013-.003A.11.11 0 0 1 15 3.42l.633-1.738a.108.108 0 0 1 .096-.073zm-8.352.366a.112.112 0 0 1 .105.064l.393.838a.112.112 0 0 1-.055.148l-.008.004a.11.11 0 0 1-.146-.054l-.395-.838a.112.112 0 0 1 .055-.149l.008-.004a.11.11 0 0 1 .043-.01zm9.246 0a.11.11 0 0 1 .043.01l.006.003a.11.11 0 0 1 .053.149l-.391.838a.112.112 0 0 1-.148.054l-.006-.002a.112.112 0 0 1-.055-.148l.393-.84a.112.112 0 0 1 .105-.064zm-10.092.44c.04-.002.08.018.102.056l.922 1.597a.113.113 0 0 1-.041.155l-.006.002a.113.113 0 0 1-.154-.041l-.922-1.598a.113.113 0 0 1 .04-.154l.007-.002a.11.11 0 0 1 .052-.016zm10.94.001c.018 0 .035.004.052.014l.004.002a.114.114 0 0 1 .041.156l-.923 1.596a.114.114 0 0 1-.157.04l-.004-.001a.112.112 0 0 1-.04-.155l.925-1.595a.113.113 0 0 1 .102-.057zM5.729 2.93a.11.11 0 0 1 .093.047l.532.753a.114.114 0 0 1-.028.159l-.004.002a.114.114 0 0 1-.158-.028l-.531-.752a.114.114 0 0 1 .027-.158l.006-.002a.113.113 0 0 1 .063-.021zm12.542 0a.11.11 0 0 1 .063.02l.006.003a.112.112 0 0 1 .027.156l-.531.756a.112.112 0 0 1-.156.028l-.006-.004a.112.112 0 0 1-.028-.157l.532-.755a.11.11 0 0 1 .093-.047zm.747.578a.11.11 0 0 1 .08.027l.006.004c.047.04.053.111.013.158L17.932 5.11a.11.11 0 0 1-.157.016l-.005-.006a.11.11 0 0 1-.014-.156l1.185-1.414a.114.114 0 0 1 .077-.041zM4.984 3.51a.11.11 0 0 1 .077.039L6.244 4.96a.112.112 0 0 1-.014.158l-.003.004a.112.112 0 0 1-.159-.014L4.883 3.697a.112.112 0 0 1 .013-.158l.006-.004a.111.111 0 0 1 .082-.025zm-.714.64c.027 0 .055.01.076.032l.658.66a.107.107 0 0 1 0 .152l-.01.01a.107.107 0 0 1-.152 0l-.66-.658a.11.11 0 0 1 0-.155l.01-.01a.111.111 0 0 1 .078-.03zm15.462 0c.028 0 .055.01.077.032l.007.007a.109.109 0 0 1 0 .155l-.658.66a.109.109 0 0 1-.154 0l-.008-.008a.109.109 0 0 1 0-.154l.658-.66a.11.11 0 0 1 .078-.032zm.707.66c.038 0 .071.02.092.075a.112.112 0 0 1-.023.117l-7.606 8.08c-3.084 2.024-6.149 4.04-9.222 6.05-.078.051-.17.082-.211-.028a.112.112 0 0 1 .023-.118l7.594-8.08c3.084-2.023 6.161-4.039 9.234-6.049a.247.247 0 0 1 .12-.046zm-16.824.045a.109.109 0 0 1 .08.026l1.416 1.187a.11.11 0 0 1 .014.157l-.006.005a.11.11 0 0 1-.156.014L3.549 5.057a.109.109 0 0 1-.014-.155l.006-.007a.108.108 0 0 1 .074-.04zm17.336.756c.036 0 .072.017.094.05l.004.003a.114.114 0 0 1-.028.158l-.753.53a.112.112 0 0 1-.157-.028l-.004-.004a.114.114 0 0 1 .028-.158l.754-.53a.113.113 0 0 1 .062-.02zm-17.904.002c.02 0 .042.007.06.02l.76.531c.05.035.06.103.026.152l-.006.01a.109.109 0 0 1-.153.026l-.76-.532a.109.109 0 0 1-.025-.152l.006-.01a.108.108 0 0 1 .092-.045zm-.512.803c.018 0 .036.006.053.016l1.596.923a.111.111 0 0 1 .04.153l-.003.006a.111.111 0 0 1-.153.04L2.473 6.63a.111.111 0 0 1-.041-.152l.004-.006a.11.11 0 0 1 .1-.055zm18.932 0a.11.11 0 0 1 .1.055l.001.004a.113.113 0 0 1-.04.154l-1.596.926a.113.113 0 0 1-.155-.041l-.002-.004a.113.113 0 0 1 .041-.155l1.596-.925a.115.115 0 0 1 .055-.014zm-19.373.846c.014 0 .029.003.043.01l.838.392a.11.11 0 0 1 .052.147l-.004.01a.11.11 0 0 1-.146.052l-.838-.393a.11.11 0 0 1-.053-.146l.004-.01a.109.109 0 0 1 .104-.062zm19.81.002a.11.11 0 0 1 .106.062l.002.008a.11.11 0 0 1-.053.146l-.838.393a.11.11 0 0 1-.146-.053l-.004-.008a.11.11 0 0 1 .052-.146l.838-.393a.11.11 0 0 1 .043-.01zm-20.183.88c.014 0 .028.001.043.006l1.732.631a.112.112 0 0 1 .067.145l-.002.006a.11.11 0 0 1-.143.066l-1.732-.63a.113.113 0 0 1-.069-.145l.002-.004a.115.115 0 0 1 .102-.074zm20.549 0a.113.113 0 0 1 .11.075l.003.004a.115.115 0 0 1-.069.146l-1.732.629a.112.112 0 0 1-.145-.066l-.001-.006a.113.113 0 0 1 .068-.145l1.732-.63a.11.11 0 0 1 .034-.006zm-20.836.909a.11.11 0 0 1 .033.004l.892.24c.06.016.096.077.08.137l-.002.007a.11.11 0 0 1-.136.079l-.895-.239a.113.113 0 0 1-.078-.138l.002-.006a.113.113 0 0 1 .104-.084zm21.13.002a.115.115 0 0 1 .106.084v.004a.112.112 0 0 1-.078.138l-.893.239a.112.112 0 0 1-.138-.079v-.005a.112.112 0 0 1 .078-.14l.892-.237a.11.11 0 0 1 .033-.004zm-21.335.93.023.001 1.814.323c.062.01.101.069.09.13v.006a.111.111 0 0 1-.13.09l-1.815-.322a.113.113 0 0 1-.092-.131l.002-.006a.11.11 0 0 1 .108-.092zm21.519.001h.022c.052.002.1.038.109.092v.006c.01.062-.03.12-.092.13l-1.814.321a.113.113 0 0 1-.131-.092v-.005a.113.113 0 0 1 .092-.131l1.814-.32zm-21.644.944h.011l.922.084a.11.11 0 0 1 .102.119l-.002.01a.11.11 0 0 1-.121.1l-.922-.083a.11.11 0 0 1-.1-.12v-.009a.111.111 0 0 1 .11-.101zm21.779.002h.012c.056 0 .106.043.11.101v.008a.111.111 0 0 1-.1.121l-.923.08a.111.111 0 0 1-.12-.101v-.008a.111.111 0 0 1 .1-.121l.92-.08zm-11.82.73L6.091 16.95c2.02-1.324 4.039-2.646 6.066-3.976l-1.095-1.31zm11.87.219c.063 0 .114.05.114.113v.004c0 .063-.05.113-.113.113l-1.844.004a.113.113 0 0 1-.113-.113v-.004c0-.063.05-.113.113-.113l1.844-.004zm-21.869.002h1.844c.062 0 .112.05.112.111v.008c0 .062-.05.111-.112.111H1.064a.111.111 0 0 1-.11-.111v-.008c0-.061.049-.111.11-.111zm.952.875h.011a.11.11 0 0 1 .11.101v.006a.111.111 0 0 1-.102.121l-.922.08a.11.11 0 0 1-.119-.101l-.002-.006a.111.111 0 0 1 .102-.121l.922-.08zm19.955 0h.011l.922.08a.11.11 0 0 1 .102.119v.008a.112.112 0 0 1-.121.101l-.922-.08a.11.11 0 0 1-.102-.119v-.008a.111.111 0 0 1 .11-.101zm-18.924.705c.053.001.098.04.107.094l.002.004c.011.061-.03.12-.092.13l-1.812.32a.113.113 0 0 1-.13-.091v-.004a.115.115 0 0 1 .09-.133l1.811-.318a.117.117 0 0 1 .024-.002zm17.902 0c.008 0 .016 0 .024.002l1.816.32c.061.011.1.07.09.131v.004a.113.113 0 0 1-.131.092l-1.816-.32a.112.112 0 0 1-.09-.131v-.004a.113.113 0 0 1 .107-.094zM2.332 14.477a.11.11 0 0 1 .104.082l.002.005c.016.06-.02.121-.08.137l-.891.24a.112.112 0 0 1-.137-.08l-.002-.006a.112.112 0 0 1 .08-.136l.89-.239a.112.112 0 0 1 .034-.003zm19.332 0c.011 0 .024 0 .035.003l.893.239c.06.016.096.077.08.136l-.002.006a.111.111 0 0 1-.137.078l-.894-.238a.111.111 0 0 1-.078-.137l.002-.005a.109.109 0 0 1 .101-.082zm-18.213.517a.11.11 0 0 1 .11.074l.002.004a.112.112 0 0 1-.067.145l-1.732.63a.113.113 0 0 1-.145-.068l-.002-.004a.113.113 0 0 1 .069-.144L3.418 15a.11.11 0 0 1 .033-.006zm17.086 0c.015 0 .029 0 .043.006l1.734.63a.111.111 0 0 1 .067.143l-.002.008a.111.111 0 0 1-.143.067l-1.734-.631a.111.111 0 0 1-.066-.143l.002-.008a.111.111 0 0 1 .1-.072zM2.92 16.117a.109.109 0 0 1 .103.063l.004.01a.108.108 0 0 1-.052.144l-.838.393a.11.11 0 0 1-.147-.055l-.004-.008a.11.11 0 0 1 .053-.146l.838-.391a.112.112 0 0 1 .043-.01zm18.158 0a.11.11 0 0 1 .043.01l.838.39c.056.027.08.093.055.149l-.002.004a.112.112 0 0 1-.149.055l-.838-.391a.112.112 0 0 1-.054-.148l.002-.004a.112.112 0 0 1 .105-.065zm-16.957.315c.04-.001.078.02.1.056l.004.004a.11.11 0 0 1-.041.153l-1.596.921a.113.113 0 0 1-.154-.04l-.002-.005a.113.113 0 0 1 .04-.154l1.596-.922a.109.109 0 0 1 .053-.013zm15.756 0c.018 0 .036.004.053.013l1.597.924a.11.11 0 0 1 .041.152l-.002.004a.11.11 0 0 1-.152.041l-1.598-.921a.113.113 0 0 1-.04-.155l.001-.002a.111.111 0 0 1 .1-.056zm.328 1.193a.11.11 0 0 1 .06.021l.758.534c.05.035.061.102.026.152l-.004.008a.111.111 0 0 1-.154.027l-.756-.535a.109.109 0 0 1-.028-.152l.006-.008a.11.11 0 0 1 .092-.047zm-16.412.002c.035 0 .072.016.094.047l.004.008a.109.109 0 0 1-.028.152l-.756.531a.108.108 0 0 1-.152-.025l-.006-.008a.109.109 0 0 1 .028-.152l.755-.534a.107.107 0 0 1 .061-.019zm15.162.102a.112.112 0 0 1 .082.025l1.414 1.187a.11.11 0 0 1 .014.157l-.004.004a.113.113 0 0 1-.158.013L18.89 17.93a.11.11 0 0 1-.014-.157l.004-.005a.108.108 0 0 1 .074-.04zm-12.812 1.12a.11.11 0 0 1 .08.026l.007.008a.11.11 0 0 1 .014.154L5.06 20.451a.11.11 0 0 1-.155.012l-.008-.006a.11.11 0 0 1-.013-.154l1.185-1.414a.11.11 0 0 1 .075-.04zm11.703 0c.032 0 .065.015.088.042l1.181 1.41c.04.048.035.12-.013.16l-.002.002a.114.114 0 0 1-.16-.014l-1.182-1.41a.114.114 0 0 1 .013-.16l.002-.002a.115.115 0 0 1 .073-.027zm-12.928.114c.027 0 .054.01.074.031l.014.012a.107.107 0 0 1 0 .15l-.662.66a.105.105 0 0 1-.149 0l-.011-.011a.105.105 0 0 1 0-.149l.66-.662a.105.105 0 0 1 .074-.031zm14.164 0c.027 0 .053.01.074.031l.66.662a.106.106 0 0 1 0 .15l-.011.012a.106.106 0 0 1-.15-.002l-.66-.66a.106.106 0 0 1 .001-.15l.01-.012a.108.108 0 0 1 .076-.031zm-11.627.797c.018 0 .034.006.05.015l.007.004a.11.11 0 0 1 .04.15l-.921 1.598a.11.11 0 0 1-.15.041l-.008-.004a.111.111 0 0 1-.04-.152l.922-1.596a.113.113 0 0 1 .1-.056zm9.088.002a.11.11 0 0 1 .1.054l.925 1.596a.113.113 0 0 1-.04.154h-.005a.11.11 0 0 1-.152-.039l-.926-1.595a.113.113 0 0 1 .041-.155l.004-.002a.108.108 0 0 1 .053-.013zm-10.285.324c.021 0 .043.008.062.021l.004.002c.051.036.063.106.028.157l-.53.755a.112.112 0 0 1-.156.028l-.004-.002a.112.112 0 0 1-.027-.156l.53-.756a.113.113 0 0 1 .093-.05zm11.484.002c.036 0 .072.015.094.047l.53.756c.035.05.023.12-.028.156l-.004.002a.112.112 0 0 1-.156-.028l-.53-.755a.112.112 0 0 1 .028-.157l.004-.002a.112.112 0 0 1 .062-.02zm-8.863.342a.11.11 0 0 1 .043.006l.012.005c.056.02.084.081.064.137l-.633 1.74a.105.105 0 0 1-.136.063l-.014-.004a.106.106 0 0 1-.065-.137l.633-1.74a.107.107 0 0 1 .096-.07zm6.232 0a.107.107 0 0 1 .106.07l.633 1.738a.107.107 0 0 1-.065.137l-.015.006a.107.107 0 0 1-.137-.065L15 20.578a.107.107 0 0 1 .064-.137l.014-.005a.117.117 0 0 1 .033-.006zm-4.695.41c.008 0 .014 0 .021.002l.006.002c.062.01.101.067.09.129l-.318 1.812a.113.113 0 0 1-.131.092l-.004-.002a.111.111 0 0 1-.092-.129l.32-1.812a.113.113 0 0 1 .108-.094zm3.146.002c.008-.002.015 0 .022 0a.111.111 0 0 1 .107.092l.32 1.812c.012.061-.03.12-.091.131l-.004.002a.113.113 0 0 1-.13-.092l-.321-1.812a.113.113 0 0 1 .092-.131l.005-.002zm-5.79.119a.11.11 0 0 1 .042.01l.004.002a.114.114 0 0 1 .055.15l-.393.834a.112.112 0 0 1-.148.055l-.004-.002a.112.112 0 0 1-.055-.149l.393-.836a.112.112 0 0 1 .105-.064zm8.458 0a.108.108 0 0 1 .104.062l.39.84a.11.11 0 0 1-.052.147l-.008.004a.11.11 0 0 1-.146-.055l-.391-.838a.11.11 0 0 1 .053-.146l.008-.004a.11.11 0 0 1 .042-.01zm-4.236.018H12c.063 0 .115.05.115.113l.002 1.84c0 .063-.05.113-.113.113h-.006a.113.113 0 0 1-.113-.113l-.004-1.838c0-.063.05-.115.113-.115zm-2.592.578c.011 0 .022 0 .034.004l.005.002c.06.016.095.077.079.136l-.24.893a.111.111 0 0 1-.137.078l-.006-.002a.111.111 0 0 1-.078-.137l.24-.89a.113.113 0 0 1 .103-.084zm5.196.002a.11.11 0 0 1 .103.082l.24.89a.11.11 0 0 1-.078.137l-.006.002a.11.11 0 0 1-.136-.078l-.24-.89a.11.11 0 0 1 .078-.138l.005-.002a.112.112 0 0 1 .034-.003zm-3.475.302h.01l.008.002c.061.006.107.06.101.121l-.08.92a.112.112 0 0 1-.121.102h-.008a.11.11 0 0 1-.1-.121l.08-.922a.111.111 0 0 1 .11-.102zm1.736 0h.02a.11.11 0 0 1 .107.102l.08.924a.11.11 0 0 1-.101.119l-.008.002a.11.11 0 0 1-.12-.102l-.08-.924a.112.112 0 0 1 .102-.12z',
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** A browser's logo in its brand colour. Decorative: pair it with a label. */
|
|
29
|
+
export function BrowserIcon({ browser, className }: { browser: BrowserName; className?: string }) {
|
|
30
|
+
const { color, path } = LOGOS[browser]
|
|
31
|
+
return (
|
|
32
|
+
<svg viewBox="0 0 24 24" fill={color} aria-hidden className={cn('size-4', className)}>
|
|
33
|
+
<path d={path} />
|
|
34
|
+
</svg>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type ReactNode, useState } from 'react'
|
|
2
|
+
import { cn } from '../lib/utils'
|
|
3
|
+
import { Badge } from '../ui/badge'
|
|
4
|
+
import { Card, CardContent, CardHeader } from '../ui/card'
|
|
5
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../ui/collapsible'
|
|
6
|
+
import { ChevronRightIcon } from './icons'
|
|
7
|
+
|
|
8
|
+
interface CollapsibleCardProps {
|
|
9
|
+
title: ReactNode
|
|
10
|
+
icon?: ReactNode
|
|
11
|
+
/** Shown as a badge beside the title when above zero, so a closed card still says whether it holds anything. */
|
|
12
|
+
count?: number
|
|
13
|
+
/** Header controls kept outside the toggle, e.g. an Edit button. */
|
|
14
|
+
actions?: ReactNode
|
|
15
|
+
open?: boolean
|
|
16
|
+
defaultOpen?: boolean
|
|
17
|
+
onOpenChange?: (open: boolean) => void
|
|
18
|
+
children: ReactNode
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** A secondary card that starts folded to its header, for content most visits don't need. */
|
|
22
|
+
export function CollapsibleCard({
|
|
23
|
+
title,
|
|
24
|
+
icon,
|
|
25
|
+
count = 0,
|
|
26
|
+
actions,
|
|
27
|
+
open,
|
|
28
|
+
defaultOpen = false,
|
|
29
|
+
onOpenChange,
|
|
30
|
+
children,
|
|
31
|
+
}: CollapsibleCardProps) {
|
|
32
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen)
|
|
33
|
+
const isOpen = open ?? uncontrolledOpen
|
|
34
|
+
|
|
35
|
+
function setOpen(next: boolean) {
|
|
36
|
+
if (open === undefined) setUncontrolledOpen(next)
|
|
37
|
+
onOpenChange?.(next)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Card>
|
|
42
|
+
<Collapsible open={isOpen} onOpenChange={setOpen}>
|
|
43
|
+
<CardHeader
|
|
44
|
+
className={cn('flex flex-row items-center gap-2 py-1.5', !isOpen && 'border-b-0')}
|
|
45
|
+
>
|
|
46
|
+
<CollapsibleTrigger className="group -mx-1 flex min-w-0 flex-1 cursor-pointer items-center gap-2 rounded-md px-1 py-1 text-left hover:bg-accent/50">
|
|
47
|
+
<ChevronRightIcon className="size-4 shrink-0 text-muted-foreground transition-transform group-data-[panel-open]:rotate-90 motion-reduce:transition-none" />
|
|
48
|
+
{/* CardTitle's styling on a span: a button may only hold phrasing content. */}
|
|
49
|
+
<span
|
|
50
|
+
data-slot="card-title"
|
|
51
|
+
className="flex items-center gap-2 text-base font-semibold"
|
|
52
|
+
>
|
|
53
|
+
{icon}
|
|
54
|
+
{title}
|
|
55
|
+
</span>
|
|
56
|
+
{count > 0 && <Badge variant="secondary">{count}</Badge>}
|
|
57
|
+
</CollapsibleTrigger>
|
|
58
|
+
{actions}
|
|
59
|
+
</CardHeader>
|
|
60
|
+
<CollapsibleContent>
|
|
61
|
+
<CardContent>{children}</CardContent>
|
|
62
|
+
</CollapsibleContent>
|
|
63
|
+
</Collapsible>
|
|
64
|
+
</Card>
|
|
65
|
+
)
|
|
66
|
+
}
|
package/src/spree/icons.ts
CHANGED
|
@@ -149,8 +149,10 @@ export {
|
|
|
149
149
|
SunIcon,
|
|
150
150
|
SwatchBookIcon,
|
|
151
151
|
TableIcon,
|
|
152
|
+
TabletIcon,
|
|
152
153
|
TagIcon,
|
|
153
154
|
TagsIcon,
|
|
155
|
+
TerminalIcon,
|
|
154
156
|
TicketPercentIcon,
|
|
155
157
|
Trash2Icon,
|
|
156
158
|
TrashIcon,
|
|
@@ -175,3 +177,4 @@ export {
|
|
|
175
177
|
XIcon,
|
|
176
178
|
ZapIcon,
|
|
177
179
|
} from 'lucide-react'
|
|
180
|
+
export { BrowserIcon, type BrowserName } from './browser-icon'
|
|
@@ -1,46 +1,101 @@
|
|
|
1
1
|
import { Fragment } from 'react'
|
|
2
|
-
import { Card, CardContent, CardHeader, CardTitle } from '../../ui/card'
|
|
3
2
|
import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '../../ui/empty'
|
|
3
|
+
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '../../ui/sheet'
|
|
4
|
+
import { CollapsibleCard } from '../collapsible-card'
|
|
5
|
+
import { CopyToClipboardButton } from '../copy-to-clipboard-button'
|
|
4
6
|
import { BracesIcon } from '../icons'
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Free-form metadata stored on a record. Read-only — apps and integrations
|
|
10
|
+
* write to it; admins just see what's there.
|
|
11
|
+
*/
|
|
12
|
+
type Metadata = Record<string, unknown> | null | undefined
|
|
13
|
+
|
|
14
|
+
/** The keys external systems (ERP, PIM, CRM) know a record by, as `{ system => key }`. */
|
|
15
|
+
type ExternalReferences = Record<string, string> | null | undefined
|
|
16
|
+
|
|
17
|
+
interface MetadataListProps {
|
|
18
|
+
metadata: Metadata
|
|
19
|
+
externalReferences?: ExternalReferences
|
|
20
|
+
/** Translated copy (passed by the app — these components stay headless). */
|
|
15
21
|
emptyTitle: string
|
|
16
22
|
emptyDescription: string
|
|
23
|
+
/** Section headings, shown only when the record has both kinds of data. */
|
|
24
|
+
metadataTitle?: string
|
|
25
|
+
externalReferencesTitle?: string
|
|
26
|
+
/** Accessible label for the copy button next to a system's key. */
|
|
27
|
+
copyLabel?: (system: string) => string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function hasMetadata(metadata: Metadata): metadata is Record<string, unknown> {
|
|
31
|
+
return !!metadata && Object.keys(metadata).length > 0
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function hasExternalReferences(
|
|
35
|
+
externalReferences: ExternalReferences,
|
|
36
|
+
): externalReferences is Record<string, string> {
|
|
37
|
+
return !!externalReferences && Object.keys(externalReferences).length > 0
|
|
17
38
|
}
|
|
18
39
|
|
|
19
|
-
export function
|
|
20
|
-
|
|
40
|
+
export function MetadataList({
|
|
41
|
+
metadata,
|
|
42
|
+
externalReferences,
|
|
43
|
+
emptyTitle,
|
|
44
|
+
emptyDescription,
|
|
45
|
+
metadataTitle,
|
|
46
|
+
externalReferencesTitle,
|
|
47
|
+
copyLabel,
|
|
48
|
+
}: MetadataListProps) {
|
|
49
|
+
const showMetadata = hasMetadata(metadata)
|
|
50
|
+
const showReferences = hasExternalReferences(externalReferences)
|
|
51
|
+
|
|
52
|
+
if (!showMetadata && !showReferences) {
|
|
53
|
+
return (
|
|
54
|
+
<Empty className="border-0 p-0">
|
|
55
|
+
<EmptyHeader>
|
|
56
|
+
<EmptyMedia variant="icon">
|
|
57
|
+
<BracesIcon />
|
|
58
|
+
</EmptyMedia>
|
|
59
|
+
<EmptyTitle>{emptyTitle}</EmptyTitle>
|
|
60
|
+
<EmptyDescription>{emptyDescription}</EmptyDescription>
|
|
61
|
+
</EmptyHeader>
|
|
62
|
+
</Empty>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const both = showMetadata && showReferences
|
|
21
67
|
|
|
22
68
|
return (
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
69
|
+
<div className="flex flex-col gap-4">
|
|
70
|
+
{showReferences && (
|
|
71
|
+
<section className="flex flex-col gap-2">
|
|
72
|
+
{externalReferencesTitle && (
|
|
73
|
+
<h4 className="text-xs font-medium text-muted-foreground">{externalReferencesTitle}</h4>
|
|
74
|
+
)}
|
|
75
|
+
<dl className="grid grid-cols-[minmax(160px,1fr)_2fr] items-center gap-x-4 gap-y-1 text-sm">
|
|
76
|
+
{Object.entries(externalReferences).map(([system, key]) => (
|
|
77
|
+
<Fragment key={system}>
|
|
78
|
+
<dt>
|
|
79
|
+
<code className="text-xs text-muted-foreground">{system}</code>
|
|
80
|
+
</dt>
|
|
81
|
+
<dd className="flex min-w-0 items-center gap-1 font-mono text-xs text-foreground/90">
|
|
82
|
+
<span className="break-all">{key}</span>
|
|
83
|
+
{copyLabel && (
|
|
84
|
+
<CopyToClipboardButton value={key} aria-label={copyLabel(system)} />
|
|
85
|
+
)}
|
|
86
|
+
</dd>
|
|
87
|
+
</Fragment>
|
|
88
|
+
))}
|
|
89
|
+
</dl>
|
|
90
|
+
</section>
|
|
91
|
+
)}
|
|
92
|
+
{showMetadata && (
|
|
93
|
+
<section className="flex flex-col gap-2">
|
|
94
|
+
{both && metadataTitle && (
|
|
95
|
+
<h4 className="text-xs font-medium text-muted-foreground">{metadataTitle}</h4>
|
|
96
|
+
)}
|
|
42
97
|
<dl className="grid grid-cols-[minmax(160px,1fr)_2fr] gap-x-4 gap-y-2 text-sm">
|
|
43
|
-
{entries.map(([key, value]) => (
|
|
98
|
+
{Object.entries(metadata).map(([key, value]) => (
|
|
44
99
|
<Fragment key={key}>
|
|
45
100
|
<dt>
|
|
46
101
|
<code className="text-xs text-muted-foreground">{key}</code>
|
|
@@ -51,9 +106,59 @@ export function MetadataCard({ metadata, title, emptyTitle, emptyDescription }:
|
|
|
51
106
|
</Fragment>
|
|
52
107
|
))}
|
|
53
108
|
</dl>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
</
|
|
109
|
+
</section>
|
|
110
|
+
)}
|
|
111
|
+
</div>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
interface MetadataCardProps extends MetadataListProps {
|
|
116
|
+
title: string
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Folded by default: metadata is for integrations, and the entry count says whether there is any. */
|
|
120
|
+
export function MetadataCard({ title, ...listProps }: MetadataCardProps) {
|
|
121
|
+
return (
|
|
122
|
+
<CollapsibleCard
|
|
123
|
+
title={title}
|
|
124
|
+
icon={<BracesIcon className="size-4" />}
|
|
125
|
+
count={
|
|
126
|
+
Object.keys(listProps.metadata ?? {}).length +
|
|
127
|
+
Object.keys(listProps.externalReferences ?? {}).length
|
|
128
|
+
}
|
|
129
|
+
>
|
|
130
|
+
<MetadataList {...listProps} />
|
|
131
|
+
</CollapsibleCard>
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
interface MetadataSheetProps extends MetadataListProps {
|
|
136
|
+
open: boolean
|
|
137
|
+
onOpenChange: (open: boolean) => void
|
|
138
|
+
title: string
|
|
139
|
+
description?: string
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Metadata of a record listed inside another page, opened from its row menu. */
|
|
143
|
+
export function MetadataSheet({
|
|
144
|
+
open,
|
|
145
|
+
onOpenChange,
|
|
146
|
+
title,
|
|
147
|
+
description,
|
|
148
|
+
...listProps
|
|
149
|
+
}: MetadataSheetProps) {
|
|
150
|
+
return (
|
|
151
|
+
<Sheet open={open} onOpenChange={onOpenChange}>
|
|
152
|
+
<SheetContent>
|
|
153
|
+
<SheetHeader>
|
|
154
|
+
<SheetTitle>{title}</SheetTitle>
|
|
155
|
+
{description && <SheetDescription>{description}</SheetDescription>}
|
|
156
|
+
</SheetHeader>
|
|
157
|
+
<div className="flex-1 overflow-y-auto p-4">
|
|
158
|
+
<MetadataList {...listProps} />
|
|
159
|
+
</div>
|
|
160
|
+
</SheetContent>
|
|
161
|
+
</Sheet>
|
|
57
162
|
)
|
|
58
163
|
}
|
|
59
164
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { cn } from '../lib/utils'
|
|
2
|
+
|
|
3
|
+
const R = 6.5
|
|
4
|
+
const CIRCUMFERENCE = 2 * Math.PI * R
|
|
5
|
+
|
|
6
|
+
/** Progress through a checklist as a ring that fills green. */
|
|
7
|
+
export function StepProgressRing({
|
|
8
|
+
value,
|
|
9
|
+
max,
|
|
10
|
+
className,
|
|
11
|
+
}: {
|
|
12
|
+
value: number
|
|
13
|
+
max: number
|
|
14
|
+
className?: string
|
|
15
|
+
}) {
|
|
16
|
+
return (
|
|
17
|
+
<svg viewBox="0 0 16 16" className={cn('size-4 shrink-0 -rotate-90', className)} aria-hidden>
|
|
18
|
+
<circle cx="8" cy="8" r={R} fill="none" strokeWidth="1.5" className="stroke-border" />
|
|
19
|
+
<circle
|
|
20
|
+
cx="8"
|
|
21
|
+
cy="8"
|
|
22
|
+
r={R}
|
|
23
|
+
fill="none"
|
|
24
|
+
strokeWidth="1.5"
|
|
25
|
+
strokeLinecap="round"
|
|
26
|
+
strokeDasharray={CIRCUMFERENCE}
|
|
27
|
+
strokeDashoffset={CIRCUMFERENCE * (1 - value / (max || 1))}
|
|
28
|
+
className="stroke-success"
|
|
29
|
+
/>
|
|
30
|
+
</svg>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type StepStatus = 'done' | 'in_progress' | 'todo'
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* A checklist step's state: a green check once done, a dashed blue ring while
|
|
38
|
+
* it is started but waiting on someone else (such as a review), and a plain
|
|
39
|
+
* ring before it is started.
|
|
40
|
+
*/
|
|
41
|
+
export function StepIcon({ status, className }: { status: StepStatus; className?: string }) {
|
|
42
|
+
const classes = cn('size-4 shrink-0', className)
|
|
43
|
+
|
|
44
|
+
if (status === 'done') {
|
|
45
|
+
return (
|
|
46
|
+
<svg viewBox="0 0 16 16" className={classes} aria-hidden>
|
|
47
|
+
<circle cx="8" cy="8" r="7.5" className="fill-success" />
|
|
48
|
+
<path
|
|
49
|
+
d="M5 8.2 7 10.2 11 6"
|
|
50
|
+
fill="none"
|
|
51
|
+
stroke="white"
|
|
52
|
+
strokeWidth="1.75"
|
|
53
|
+
strokeLinecap="round"
|
|
54
|
+
strokeLinejoin="round"
|
|
55
|
+
/>
|
|
56
|
+
</svg>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<svg viewBox="0 0 16 16" className={classes} aria-hidden>
|
|
62
|
+
<circle
|
|
63
|
+
cx="8"
|
|
64
|
+
cy="8"
|
|
65
|
+
r={R}
|
|
66
|
+
fill="none"
|
|
67
|
+
strokeWidth="1.5"
|
|
68
|
+
strokeLinecap="round"
|
|
69
|
+
strokeDasharray={status === 'in_progress' ? '2.5 2.6' : undefined}
|
|
70
|
+
className={status === 'in_progress' ? 'stroke-blue-500' : 'stroke-border'}
|
|
71
|
+
/>
|
|
72
|
+
</svg>
|
|
73
|
+
)
|
|
74
|
+
}
|
package/src/styles.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
@import "tailwindcss";
|
|
2
2
|
@import "tw-animate-css";
|
|
3
|
-
@import "shadcn
|
|
3
|
+
@import "./shadcn.css";
|
|
4
4
|
@import "@fontsource-variable/geist";
|
|
5
5
|
@import "@fontsource-variable/geist-mono";
|
|
6
6
|
|
|
@@ -450,8 +450,8 @@
|
|
|
450
450
|
--radius-sm: 0.4rem;
|
|
451
451
|
--radius-md: 0.5rem;
|
|
452
452
|
--radius-lg: 0.625rem;
|
|
453
|
-
--radius-xl: 0.
|
|
454
|
-
--radius-2xl:
|
|
453
|
+
--radius-xl: 0.75rem;
|
|
454
|
+
--radius-2xl: 1rem;
|
|
455
455
|
|
|
456
456
|
/* Sidebar + header tokens */
|
|
457
457
|
--spacing-sidebar-width: 240px;
|
package/src/ui/badge.tsx
CHANGED
|
@@ -78,6 +78,9 @@ type StatusTone = 'success' | 'warning' | 'destructive' | 'info' | 'neutral'
|
|
|
78
78
|
*/
|
|
79
79
|
const statusToneMap: Record<string, StatusTone> = {
|
|
80
80
|
active: 'success',
|
|
81
|
+
// Staff accounts: locked after too many failed sign-ins, deactivated by an admin.
|
|
82
|
+
locked: 'warning',
|
|
83
|
+
deactivated: 'neutral',
|
|
81
84
|
authorized: 'info',
|
|
82
85
|
complete: 'success',
|
|
83
86
|
completed: 'success',
|