polishing next home hero visual (#19284)
**Summary** - update the home hero navbar controls and surface styling to better match the latest visual design - simplify row hover actions by removing edit affordances and disabling hover controls for `createdBy` and `accountOwner` - tighten chip typography and spacing for more consistent hero table rendering - include the captured Playwright screenshot artifact for reference **Testing** - Not run (not requested)
This commit is contained in:
committed by
GitHub
parent
04d22feef6
commit
175ae5f0aa
@@ -52,3 +52,4 @@ mcp.json
|
|||||||
/.junie/
|
/.junie/
|
||||||
TRANSLATION_QA_REPORT.md
|
TRANSLATION_QA_REPORT.md
|
||||||
.playwright-mcp/
|
.playwright-mcp/
|
||||||
|
.playwright-cli/
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" viewBox="0 0 89.89 104.6"><defs><clipPath id="a"><path d="M150.97 50.8c-9.07.38-19.66 3.95-25.85 8.6-5.62 4.21-10.26 10.47-8.46 16.56 9.9.19 20.13-3.47 26.07-8.18 5.55-4.4 9.77-10.63 8.24-16.99m3.35 24.48c-15.27 0-21.72 4.49-32.31 4.49-10.92 0-19.23-4.49-32.43-4.49-12.98 0-26.77 4.88-35.51 13.21l-.16.16A24.3 24.3 0 0 0 46.88 102c-.76 4.14-.56 8.66.62 13.35a46 46 0 0 0 5.93 13.35 65 65 0 0 0 11.45 13.35c7 6.45 16.2 13.28 28.04 13.34 11.08.07 14.21-4.37 29.24-4.42s17.87 4.47 28.94 4.4c11.35-.05 20.7-7 27.67-13.32l1.98-1.83a70 70 0 0 0 10.12-11.51l.87-1.18c-9.96-2.32-17.03-6.85-20.85-12.18-3-4.18-4-8.86-2.81-13.35 1.31-4.98 5.3-9.73 12.2-13.35a45 45 0 0 1 6.52-2.76c-8.72-6.72-20.95-10.61-32.48-10.61"/></clipPath></defs><g clip-path="url(#a)" transform="matrix(.61862 0 0 1 -28.72 -50.8)"><g stroke-linecap="round"><path fill="#75bd21" d="M24.86 37.45H213.3V102H24.86z"/><path fill="#ffc728" d="M24.86 88.65H213.3v26.7H24.86z"/><path fill="#ff661c" d="M24.86 102H213.3v26.7H24.86z"/><path fill="#cf0f2b" d="M24.86 115.35H213.3v26.7H24.86z"/><path fill="#b01cab" d="M24.86 128.7H213.3v26.68H24.86z"/><path fill="#00a1de" d="M24.86 142.06H213.3v26.68H24.86z"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 976 B |
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
@@ -8,7 +8,7 @@ const PEOPLE_AVATAR_URLS = {
|
|||||||
jeffWilliams:
|
jeffWilliams:
|
||||||
'https://twentyhq.github.io/placeholder-images/people/image-22.png',
|
'https://twentyhq.github.io/placeholder-images/people/image-22.png',
|
||||||
katherineAdams:
|
katherineAdams:
|
||||||
'https://twentyhq.github.io/placeholder-images/people/image-07.png',
|
'/images/home/hero/avatars/katherine-adams.jpg',
|
||||||
philSchiller:
|
philSchiller:
|
||||||
'https://twentyhq.github.io/placeholder-images/people/image-14.png',
|
'https://twentyhq.github.io/placeholder-images/people/image-14.png',
|
||||||
timCook:
|
timCook:
|
||||||
@@ -28,66 +28,6 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
workspace: { icon: 'apple', name: 'Apple' },
|
workspace: { icon: 'apple', name: 'Apple' },
|
||||||
tableWidth: 1700,
|
tableWidth: 1700,
|
||||||
actions: ['Filter', 'Sort', 'Options'],
|
actions: ['Filter', 'Sort', 'Options'],
|
||||||
favoritesNav: [
|
|
||||||
{
|
|
||||||
id: 'fav-to-follow',
|
|
||||||
label: 'To Follow',
|
|
||||||
icon: { kind: 'tabler', name: 'folder', tone: 'orange' },
|
|
||||||
showChevron: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 'fav-stripe',
|
|
||||||
label: 'Stripe',
|
|
||||||
meta: 'Company',
|
|
||||||
icon: { kind: 'brand', brand: 'stripe' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'fav-airbnb',
|
|
||||||
label: 'Airbnb',
|
|
||||||
meta: 'Company',
|
|
||||||
icon: { kind: 'brand', brand: 'airbnb' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'fav-brian-chesky',
|
|
||||||
label: 'Brian Chesky',
|
|
||||||
meta: 'Person',
|
|
||||||
icon: {
|
|
||||||
kind: 'avatar',
|
|
||||||
label: 'B',
|
|
||||||
tone: 'violet',
|
|
||||||
shape: 'circle',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'fav-all-companies',
|
|
||||||
label: 'All Companies',
|
|
||||||
icon: { kind: 'tabler', name: 'buildingSkyscraper', tone: 'blue' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'fav-send-nda',
|
|
||||||
label: 'Send NDA to Qonto - T...',
|
|
||||||
icon: { kind: 'avatar', label: 'L', tone: 'teal', shape: 'circle' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'fav-page-layout',
|
|
||||||
label: 'Page Layout',
|
|
||||||
icon: { kind: 'brand', brand: 'page-layout' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'fav-figma',
|
|
||||||
label: 'Figma',
|
|
||||||
meta: 'Company',
|
|
||||||
icon: { kind: 'brand', brand: 'figma' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'fav-ben-chestnut',
|
|
||||||
label: 'Ben Chestnut',
|
|
||||||
meta: 'Person',
|
|
||||||
icon: { kind: 'brand', brand: 'ben-chestnut' },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
workspaceNav: [
|
workspaceNav: [
|
||||||
{
|
{
|
||||||
id: 'companies',
|
id: 'companies',
|
||||||
@@ -369,7 +309,7 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'people',
|
id: 'people',
|
||||||
label: 'People',
|
label: 'People',
|
||||||
icon: { kind: 'tabler', name: 'user', tone: 'purple' },
|
icon: { kind: 'tabler', name: 'user', tone: 'blue' },
|
||||||
viewLabel: 'All People',
|
viewLabel: 'All People',
|
||||||
viewCount: 5,
|
viewCount: 5,
|
||||||
columns: [
|
columns: [
|
||||||
@@ -414,7 +354,7 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'opportunities',
|
id: 'opportunities',
|
||||||
label: 'Opportunities',
|
label: 'Opportunities',
|
||||||
icon: { kind: 'tabler', name: 'targetArrow', tone: 'pink' },
|
icon: { kind: 'tabler', name: 'targetArrow', tone: 'red' },
|
||||||
viewLabel: 'All Opportunities',
|
viewLabel: 'All Opportunities',
|
||||||
viewCount: 3,
|
viewCount: 3,
|
||||||
columns: [
|
columns: [
|
||||||
@@ -429,7 +369,12 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'enterprise-rollout',
|
id: 'enterprise-rollout',
|
||||||
cells: {
|
cells: {
|
||||||
name: { type: 'text', value: 'Enterprise rollout' },
|
name: {
|
||||||
|
type: 'text',
|
||||||
|
value: 'Enterprise rollout',
|
||||||
|
shortLabel: 'E',
|
||||||
|
tone: 'pink',
|
||||||
|
},
|
||||||
company: { type: 'entity', name: 'Slack', domain: 'slack.com' },
|
company: { type: 'entity', name: 'Slack', domain: 'slack.com' },
|
||||||
amount: { type: 'number', value: '$2,300,000' },
|
amount: { type: 'number', value: '$2,300,000' },
|
||||||
stage: { type: 'tag', value: 'Negotiation' },
|
stage: { type: 'tag', value: 'Negotiation' },
|
||||||
@@ -440,7 +385,12 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'workspace-upgrade',
|
id: 'workspace-upgrade',
|
||||||
cells: {
|
cells: {
|
||||||
name: { type: 'text', value: 'Workspace upgrade' },
|
name: {
|
||||||
|
type: 'text',
|
||||||
|
value: 'Workspace upgrade',
|
||||||
|
shortLabel: 'W',
|
||||||
|
tone: 'pink',
|
||||||
|
},
|
||||||
company: { type: 'entity', name: 'Notion', domain: 'notion.com' },
|
company: { type: 'entity', name: 'Notion', domain: 'notion.com' },
|
||||||
amount: { type: 'number', value: '$750,000' },
|
amount: { type: 'number', value: '$750,000' },
|
||||||
stage: { type: 'tag', value: 'Qualified' },
|
stage: { type: 'tag', value: 'Qualified' },
|
||||||
@@ -467,7 +417,12 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'send-nda',
|
id: 'send-nda',
|
||||||
cells: {
|
cells: {
|
||||||
title: { type: 'text', value: 'Send NDA' },
|
title: {
|
||||||
|
type: 'text',
|
||||||
|
value: 'Send NDA',
|
||||||
|
shortLabel: 'S',
|
||||||
|
tone: 'teal',
|
||||||
|
},
|
||||||
assignee: { type: 'person', name: 'Tim Cook', tone: 'teal', kind: 'person', avatarUrl: PEOPLE_AVATAR_URLS.timCook },
|
assignee: { type: 'person', name: 'Tim Cook', tone: 'teal', kind: 'person', avatarUrl: PEOPLE_AVATAR_URLS.timCook },
|
||||||
dueDate: { type: 'text', value: 'Oct 25, 2023' },
|
dueDate: { type: 'text', value: 'Oct 25, 2023' },
|
||||||
relatedTo: { type: 'entity', name: 'Anthropic', domain: 'anthropic.com' },
|
relatedTo: { type: 'entity', name: 'Anthropic', domain: 'anthropic.com' },
|
||||||
@@ -477,7 +432,12 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'review-proposal',
|
id: 'review-proposal',
|
||||||
cells: {
|
cells: {
|
||||||
title: { type: 'text', value: 'Review proposal' },
|
title: {
|
||||||
|
type: 'text',
|
||||||
|
value: 'Review proposal',
|
||||||
|
shortLabel: 'R',
|
||||||
|
tone: 'teal',
|
||||||
|
},
|
||||||
assignee: { type: 'person', name: 'Eddy Cue', tone: 'gray', kind: 'person', avatarUrl: PEOPLE_AVATAR_URLS.eddyCue },
|
assignee: { type: 'person', name: 'Eddy Cue', tone: 'gray', kind: 'person', avatarUrl: PEOPLE_AVATAR_URLS.eddyCue },
|
||||||
dueDate: { type: 'text', value: 'Oct 28, 2023' },
|
dueDate: { type: 'text', value: 'Oct 28, 2023' },
|
||||||
relatedTo: { type: 'entity', name: 'Slack', domain: 'slack.com' },
|
relatedTo: { type: 'entity', name: 'Slack', domain: 'slack.com' },
|
||||||
@@ -489,7 +449,7 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'notes',
|
id: 'notes',
|
||||||
label: 'Notes',
|
label: 'Notes',
|
||||||
icon: { kind: 'tabler', name: 'notes', tone: 'green' },
|
icon: { kind: 'tabler', name: 'notes', tone: 'teal' },
|
||||||
viewLabel: 'All Notes',
|
viewLabel: 'All Notes',
|
||||||
viewCount: 2,
|
viewCount: 2,
|
||||||
columns: [
|
columns: [
|
||||||
@@ -502,7 +462,12 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'discovery-call',
|
id: 'discovery-call',
|
||||||
cells: {
|
cells: {
|
||||||
title: { type: 'text', value: 'Discovery call notes' },
|
title: {
|
||||||
|
type: 'text',
|
||||||
|
value: 'Discovery call notes',
|
||||||
|
shortLabel: 'D',
|
||||||
|
tone: 'green',
|
||||||
|
},
|
||||||
createdBy: { type: 'person', name: 'Phil Schiller', tone: 'amber', kind: 'person', avatarUrl: PEOPLE_AVATAR_URLS.philSchiller },
|
createdBy: { type: 'person', name: 'Phil Schiller', tone: 'amber', kind: 'person', avatarUrl: PEOPLE_AVATAR_URLS.philSchiller },
|
||||||
relatedTo: { type: 'entity', name: 'Notion', domain: 'notion.com' },
|
relatedTo: { type: 'entity', name: 'Notion', domain: 'notion.com' },
|
||||||
added: { type: 'text', value: 'Sep 2, 2023' },
|
added: { type: 'text', value: 'Sep 2, 2023' },
|
||||||
@@ -511,7 +476,12 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'design-system-meeting',
|
id: 'design-system-meeting',
|
||||||
cells: {
|
cells: {
|
||||||
title: { type: 'text', value: 'Design system meeting' },
|
title: {
|
||||||
|
type: 'text',
|
||||||
|
value: 'Design system meeting',
|
||||||
|
shortLabel: 'D',
|
||||||
|
tone: 'green',
|
||||||
|
},
|
||||||
createdBy: { type: 'person', name: 'Tim Cook', tone: 'teal', kind: 'person', avatarUrl: PEOPLE_AVATAR_URLS.timCook },
|
createdBy: { type: 'person', name: 'Tim Cook', tone: 'teal', kind: 'person', avatarUrl: PEOPLE_AVATAR_URLS.timCook },
|
||||||
relatedTo: { type: 'entity', name: 'Figma', domain: 'figma.com' },
|
relatedTo: { type: 'entity', name: 'Figma', domain: 'figma.com' },
|
||||||
added: { type: 'text', value: 'Oct 18, 2023' },
|
added: { type: 'text', value: 'Oct 18, 2023' },
|
||||||
@@ -522,7 +492,7 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'sales-dashboard',
|
id: 'sales-dashboard',
|
||||||
label: 'Sales Dashboard',
|
label: 'Sales Dashboard',
|
||||||
icon: { kind: 'avatar', label: '$', tone: 'amber', shape: 'circle' },
|
icon: { kind: 'avatar', label: 'S', tone: 'amber', shape: 'circle' },
|
||||||
meta: 'Dashboard',
|
meta: 'Dashboard',
|
||||||
viewLabel: 'Sales Dashboard',
|
viewLabel: 'Sales Dashboard',
|
||||||
viewCount: 0,
|
viewCount: 0,
|
||||||
@@ -550,7 +520,12 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'new-lead',
|
id: 'new-lead',
|
||||||
cells: {
|
cells: {
|
||||||
name: { type: 'text', value: 'New Lead Assignment' },
|
name: {
|
||||||
|
type: 'text',
|
||||||
|
value: 'New Lead Assignment',
|
||||||
|
shortLabel: 'N',
|
||||||
|
tone: 'amber',
|
||||||
|
},
|
||||||
status: { type: 'tag', value: 'Active' },
|
status: { type: 'tag', value: 'Active' },
|
||||||
lastRun: { type: 'text', value: 'Oct 24, 2023 10:00 am' },
|
lastRun: { type: 'text', value: 'Oct 24, 2023 10:00 am' },
|
||||||
},
|
},
|
||||||
@@ -558,7 +533,12 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'nurture',
|
id: 'nurture',
|
||||||
cells: {
|
cells: {
|
||||||
name: { type: 'text', value: 'Nurture Sequence' },
|
name: {
|
||||||
|
type: 'text',
|
||||||
|
value: 'Nurture Sequence',
|
||||||
|
shortLabel: 'N',
|
||||||
|
tone: 'amber',
|
||||||
|
},
|
||||||
status: { type: 'tag', value: 'Inactive' },
|
status: { type: 'tag', value: 'Inactive' },
|
||||||
lastRun: { type: 'text', value: 'Oct 20, 2023 3:15 pm' },
|
lastRun: { type: 'text', value: 'Oct 20, 2023 3:15 pm' },
|
||||||
},
|
},
|
||||||
@@ -582,7 +562,12 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'run-12345',
|
id: 'run-12345',
|
||||||
cells: {
|
cells: {
|
||||||
runId: { type: 'text', value: 'run_12345' },
|
runId: {
|
||||||
|
type: 'text',
|
||||||
|
value: 'run_12345',
|
||||||
|
shortLabel: 'R',
|
||||||
|
tone: 'amber',
|
||||||
|
},
|
||||||
workflow: { type: 'text', value: 'New Lead Assignment' },
|
workflow: { type: 'text', value: 'New Lead Assignment' },
|
||||||
status: { type: 'tag', value: 'Success' },
|
status: { type: 'tag', value: 'Success' },
|
||||||
startedAt: { type: 'text', value: 'Oct 24, 2023 10:00 am' },
|
startedAt: { type: 'text', value: 'Oct 24, 2023 10:00 am' },
|
||||||
@@ -592,7 +577,12 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'run-12346',
|
id: 'run-12346',
|
||||||
cells: {
|
cells: {
|
||||||
runId: { type: 'text', value: 'run_12346' },
|
runId: {
|
||||||
|
type: 'text',
|
||||||
|
value: 'run_12346',
|
||||||
|
shortLabel: 'R',
|
||||||
|
tone: 'amber',
|
||||||
|
},
|
||||||
workflow: { type: 'text', value: 'Nurture Sequence' },
|
workflow: { type: 'text', value: 'Nurture Sequence' },
|
||||||
status: { type: 'tag', value: 'Failed' },
|
status: { type: 'tag', value: 'Failed' },
|
||||||
startedAt: { type: 'text', value: 'Oct 20, 2023 3:15 pm' },
|
startedAt: { type: 'text', value: 'Oct 20, 2023 3:15 pm' },
|
||||||
@@ -617,7 +607,12 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'v2-lead',
|
id: 'v2-lead',
|
||||||
cells: {
|
cells: {
|
||||||
version: { type: 'text', value: 'v2' },
|
version: {
|
||||||
|
type: 'text',
|
||||||
|
value: 'v2',
|
||||||
|
shortLabel: 'V',
|
||||||
|
tone: 'amber',
|
||||||
|
},
|
||||||
workflow: { type: 'text', value: 'New Lead Assignment' },
|
workflow: { type: 'text', value: 'New Lead Assignment' },
|
||||||
publishedAt: { type: 'text', value: 'Oct 15, 2023 9:00 am' },
|
publishedAt: { type: 'text', value: 'Oct 15, 2023 9:00 am' },
|
||||||
publishedBy: { type: 'person', name: 'Ivan Zhao', shortLabel: 'I', tone: 'gray', kind: 'person', avatarUrl: 'https://twentyhq.github.io/placeholder-images/people/image-09.png' },
|
publishedBy: { type: 'person', name: 'Ivan Zhao', shortLabel: 'I', tone: 'gray', kind: 'person', avatarUrl: 'https://twentyhq.github.io/placeholder-images/people/image-09.png' },
|
||||||
@@ -626,7 +621,12 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
{
|
{
|
||||||
id: 'v1-lead',
|
id: 'v1-lead',
|
||||||
cells: {
|
cells: {
|
||||||
version: { type: 'text', value: 'v1' },
|
version: {
|
||||||
|
type: 'text',
|
||||||
|
value: 'v1',
|
||||||
|
shortLabel: 'V',
|
||||||
|
tone: 'amber',
|
||||||
|
},
|
||||||
workflow: { type: 'text', value: 'New Lead Assignment' },
|
workflow: { type: 'text', value: 'New Lead Assignment' },
|
||||||
publishedAt: { type: 'text', value: 'Sep 10, 2023 1:00 pm' },
|
publishedAt: { type: 'text', value: 'Sep 10, 2023 1:00 pm' },
|
||||||
publishedBy: { type: 'person', name: 'Ivan Zhao', shortLabel: 'I', tone: 'gray', kind: 'person', avatarUrl: 'https://twentyhq.github.io/placeholder-images/people/image-09.png' },
|
publishedBy: { type: 'person', name: 'Ivan Zhao', shortLabel: 'I', tone: 'gray', kind: 'person', avatarUrl: 'https://twentyhq.github.io/placeholder-images/people/image-09.png' },
|
||||||
@@ -637,15 +637,15 @@ export const HERO_DATA: HeroHomeDataType = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'claude',
|
id: 'book-demo',
|
||||||
label: 'Claude',
|
label: 'Book a demo',
|
||||||
icon: { kind: 'brand', brand: 'claude', overlay: 'link' },
|
href: 'https://cal.com/forms/f7841033-0a20-4958-8c92-4e34ec128a81',
|
||||||
},
|
icon: {
|
||||||
{
|
kind: 'brand',
|
||||||
id: 'workspace-stripe',
|
brand: 'twenty',
|
||||||
label: 'Stripe',
|
imageSrc: '/images/home/hero/twenty-demo-logo.png',
|
||||||
icon: { kind: 'brand', brand: 'stripe' },
|
overlay: 'link',
|
||||||
showChevron: true,
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
+361
-126
@@ -5,7 +5,6 @@ import { styled } from '@linaria/react';
|
|||||||
import {
|
import {
|
||||||
IconBook,
|
IconBook,
|
||||||
IconBox,
|
IconBox,
|
||||||
IconBrandApple,
|
|
||||||
IconBrandLinkedin,
|
IconBrandLinkedin,
|
||||||
IconBuildingFactory2,
|
IconBuildingFactory2,
|
||||||
IconBuildingSkyscraper,
|
IconBuildingSkyscraper,
|
||||||
@@ -52,6 +51,7 @@ import type {
|
|||||||
HeroCellEntity,
|
HeroCellEntity,
|
||||||
HeroCellPerson,
|
HeroCellPerson,
|
||||||
HeroCellRelation,
|
HeroCellRelation,
|
||||||
|
HeroCellText,
|
||||||
HeroCellValue,
|
HeroCellValue,
|
||||||
HeroColumnDef,
|
HeroColumnDef,
|
||||||
HeroRowDef,
|
HeroRowDef,
|
||||||
@@ -66,6 +66,9 @@ import { VISUAL_TOKENS } from './homeVisualTokens';
|
|||||||
|
|
||||||
const APP_FONT = VISUAL_TOKENS.font.family;
|
const APP_FONT = VISUAL_TOKENS.font.family;
|
||||||
const DEFAULT_TABLE_WIDTH = 1700;
|
const DEFAULT_TABLE_WIDTH = 1700;
|
||||||
|
const APPLE_WORKSPACE_LOGO_SRC = '/images/home/hero/apple-rainbow-logo.svg';
|
||||||
|
const TABLE_CELL_HORIZONTAL_PADDING = 8;
|
||||||
|
const HOVER_ACTION_EDGE_INSET = 4;
|
||||||
|
|
||||||
const COLORS = {
|
const COLORS = {
|
||||||
accent: VISUAL_TOKENS.accent.accent9,
|
accent: VISUAL_TOKENS.accent.accent9,
|
||||||
@@ -88,16 +91,16 @@ const SIDEBAR_TONES: Record<
|
|||||||
string,
|
string,
|
||||||
{ background: string; border: string; color: string }
|
{ background: string; border: string; color: string }
|
||||||
> = {
|
> = {
|
||||||
amber: { background: '#fff4d6', border: '#ffd49b', color: '#9a6700' },
|
amber: { background: '#FEF2A4', border: '#FEF2A4', color: '#35290F' },
|
||||||
blue: { background: '#d9e2fc', border: '#c6d4f9', color: '#3557c6' },
|
blue: { background: '#d9e2fc', border: '#c6d4f9', color: '#3A5CCC' },
|
||||||
gray: { background: '#ebebeb', border: '#d6d6d6', color: '#666666' },
|
gray: { background: '#ebebeb', border: '#d6d6d6', color: '#838383' },
|
||||||
green: { background: '#ccebd7', border: '#bbe4c9', color: '#153226' },
|
green: { background: '#ccebd7', border: '#bbe4c9', color: '#153226' },
|
||||||
orange: { background: '#ffdcc3', border: '#ffcca7', color: '#582d1d' },
|
orange: { background: '#ffdcc3', border: '#ffcca7', color: '#ED5F00' },
|
||||||
pink: { background: '#ffe1e7', border: '#ffc8d6', color: '#a51853' },
|
pink: { background: '#ffe1e7', border: '#ffc8d6', color: '#a51853' },
|
||||||
purple: { background: '#e0e7ff', border: '#c7d2fe', color: '#4f46e5' },
|
purple: { background: '#e0e7ff', border: '#c7d2fe', color: '#4f46e5' },
|
||||||
teal: { background: '#c7ebe5', border: '#b3e3dc', color: '#10302b' },
|
teal: { background: '#c7ebe5', border: '#afdfd7', color: '#0E9888' },
|
||||||
violet: { background: '#ebe5ff', border: '#d8cbff', color: '#5b3fd1' },
|
violet: { background: '#ebe5ff', border: '#d8cbff', color: '#5b3fd1' },
|
||||||
red: { background: '#fee2e2', border: '#fecaca', color: '#b91c1c' },
|
red: { background: '#fdd8d8', border: '#f9c6c6', color: '#DC3D43' },
|
||||||
};
|
};
|
||||||
|
|
||||||
const PERSON_TONES: Record<string, { background: string; color: string }> = {
|
const PERSON_TONES: Record<string, { background: string; color: string }> = {
|
||||||
@@ -113,6 +116,10 @@ const PERSON_TONES: Record<string, { background: string; color: string }> = {
|
|||||||
|
|
||||||
const TABLER_STROKE = 1.6;
|
const TABLER_STROKE = 1.6;
|
||||||
const NAVIGATION_TABLER_STROKE = 2;
|
const NAVIGATION_TABLER_STROKE = 2;
|
||||||
|
const ROW_HOVER_ACTION_DISABLED_COLUMNS = new Set([
|
||||||
|
'createdBy',
|
||||||
|
'accountOwner',
|
||||||
|
]);
|
||||||
|
|
||||||
// -- Styled Components --
|
// -- Styled Components --
|
||||||
|
|
||||||
@@ -139,16 +146,7 @@ const ShellScene = styled.div`
|
|||||||
const Frame = styled.div`
|
const Frame = styled.div`
|
||||||
aspect-ratio: 1280 / 832;
|
aspect-ratio: 1280 / 832;
|
||||||
background-color: ${COLORS.background};
|
background-color: ${COLORS.background};
|
||||||
background-image: radial-gradient(
|
background-image: ${VISUAL_TOKENS.background.noisy};
|
||||||
circle at top center,
|
|
||||||
rgba(0, 0, 0, 0.035),
|
|
||||||
rgba(0, 0, 0, 0) 55%
|
|
||||||
),
|
|
||||||
${VISUAL_TOKENS.background.noisy};
|
|
||||||
background-position:
|
|
||||||
center top,
|
|
||||||
center;
|
|
||||||
background-repeat: no-repeat, repeat;
|
|
||||||
border: 1px solid ${COLORS.border};
|
border: 1px solid ${COLORS.border};
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: ${COLORS.shadow};
|
box-shadow: ${COLORS.shadow};
|
||||||
@@ -157,24 +155,27 @@ const Frame = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const AppLayout = styled.div`
|
const AppLayout = styled.div`
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: 72px minmax(0, 1fr);
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
@media (min-width: ${theme.breakpoints.md}px) {
|
|
||||||
grid-template-columns: 220px minmax(0, 1fr);
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SidebarPanel = styled.aside`
|
const SidebarPanel = styled.aside`
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border-right: 1px solid rgba(0, 0, 0, 0.04);
|
|
||||||
display: grid;
|
display: grid;
|
||||||
|
flex: 0 0 72px;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
grid-template-rows: auto auto minmax(0, 1fr);
|
grid-template-rows: auto auto minmax(0, 1fr);
|
||||||
|
min-height: 0;
|
||||||
padding: 12px 8px;
|
padding: 12px 8px;
|
||||||
|
width: 72px;
|
||||||
|
|
||||||
|
@media (min-width: ${theme.breakpoints.md}px) {
|
||||||
|
flex-basis: 220px;
|
||||||
|
width: 220px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SidebarTopBar = styled.div`
|
const SidebarTopBar = styled.div`
|
||||||
@@ -196,16 +197,17 @@ const WorkspaceMenu = styled.div`
|
|||||||
|
|
||||||
const WorkspaceIcon = styled.div`
|
const WorkspaceIcon = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: #111111;
|
|
||||||
border-radius: 2px;
|
|
||||||
color: #ffffff;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
font-family: ${APP_FONT};
|
flex: 0 0 auto;
|
||||||
font-size: 11px;
|
|
||||||
font-weight: ${theme.font.weight.medium};
|
|
||||||
height: 16px;
|
height: 16px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 16px;
|
width: 14px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const WorkspaceIconImage = styled.img`
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const WorkspaceLabel = styled.span`
|
const WorkspaceLabel = styled.span`
|
||||||
@@ -246,10 +248,17 @@ const SidebarControls = styled.div`
|
|||||||
display: grid;
|
display: grid;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
grid-template-columns: auto 1fr;
|
grid-template-columns: auto 1fr;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
@media (min-width: ${theme.breakpoints.md}px) {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SegmentedRail = styled.div`
|
const SegmentedRail = styled.div`
|
||||||
background: rgba(252, 252, 252, 0.8);
|
background: #fcfcfccc;
|
||||||
border: 1px solid ${COLORS.border};
|
border: 1px solid ${COLORS.border};
|
||||||
border-radius: 40px;
|
border-radius: 40px;
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -261,12 +270,17 @@ const SegmentedRail = styled.div`
|
|||||||
const Segment = styled.div<{ $selected?: boolean }>`
|
const Segment = styled.div<{ $selected?: boolean }>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: ${({ $selected }) =>
|
background: ${({ $selected }) =>
|
||||||
$selected ? 'rgba(0, 0, 0, 0.04)' : 'transparent'};
|
$selected ? '#0000000a' : 'transparent'};
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 22px;
|
width: 22px;
|
||||||
|
|
||||||
|
@media (min-width: ${theme.breakpoints.md}px) {
|
||||||
|
padding: 0 8px;
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const NewChat = styled.div`
|
const NewChat = styled.div`
|
||||||
@@ -305,8 +319,9 @@ const NewChatLabel = styled.span`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const SidebarScroll = styled.div`
|
const SidebarScroll = styled.div`
|
||||||
display: grid;
|
display: flex;
|
||||||
gap: 12px;
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
`;
|
`;
|
||||||
@@ -316,14 +331,15 @@ const SidebarSection = styled.div`
|
|||||||
gap: 2px;
|
gap: 2px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SidebarSectionLabel = styled.span`
|
const SidebarSectionLabel = styled.span<{ $workspace?: boolean }>`
|
||||||
color: ${COLORS.textLight};
|
color: ${COLORS.textLight};
|
||||||
display: none;
|
display: none;
|
||||||
font-family: ${APP_FONT};
|
font-family: ${APP_FONT};
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
padding: 0 4px 4px;
|
padding: ${({ $workspace }) =>
|
||||||
|
$workspace ? '4px 4px 8px' : '0 4px 4px'};
|
||||||
|
|
||||||
@media (min-width: ${theme.breakpoints.md}px) {
|
@media (min-width: ${theme.breakpoints.md}px) {
|
||||||
display: block;
|
display: block;
|
||||||
@@ -333,17 +349,57 @@ const SidebarSectionLabel = styled.span`
|
|||||||
const SidebarItemRow = styled.div<{
|
const SidebarItemRow = styled.div<{
|
||||||
$active?: boolean;
|
$active?: boolean;
|
||||||
$depth?: number;
|
$depth?: number;
|
||||||
|
$interactive?: boolean;
|
||||||
|
$withBranch?: boolean;
|
||||||
}>`
|
}>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: ${({ $active }) =>
|
background: ${({ $active }) =>
|
||||||
$active ? 'rgba(0, 0, 0, 0.04)' : 'transparent'};
|
$active ? VISUAL_TOKENS.background.transparent.medium : 'transparent'};
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 8px;
|
gap: 0;
|
||||||
grid-template-columns: auto minmax(0, 1fr) auto;
|
grid-template-columns: ${({ $withBranch }) =>
|
||||||
|
$withBranch ? '9px minmax(0, 1fr) auto' : 'minmax(0, 1fr) auto'};
|
||||||
height: 28px;
|
height: 28px;
|
||||||
padding: 0 2px 0 ${({ $depth = 0 }) => `${$depth === 0 ? 4 : 24}px`};
|
padding: 0 2px 0 ${({ $depth = 0 }) => `${$depth === 0 ? 4 : 11}px`};
|
||||||
position: relative;
|
position: relative;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background-color 0.14s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: ${({ $active, $interactive }) =>
|
||||||
|
$active || $interactive
|
||||||
|
? VISUAL_TOKENS.background.transparent.medium
|
||||||
|
: 'transparent'};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SidebarItemRowLink = styled.a<{
|
||||||
|
$active?: boolean;
|
||||||
|
$depth?: number;
|
||||||
|
$interactive?: boolean;
|
||||||
|
$withBranch?: boolean;
|
||||||
|
}>`
|
||||||
|
align-items: center;
|
||||||
|
background: ${({ $active }) =>
|
||||||
|
$active ? VISUAL_TOKENS.background.transparent.medium : 'transparent'};
|
||||||
|
border-radius: 4px;
|
||||||
|
display: grid;
|
||||||
|
gap: 0;
|
||||||
|
grid-template-columns: ${({ $withBranch }) =>
|
||||||
|
$withBranch ? '9px minmax(0, 1fr) auto' : 'minmax(0, 1fr) auto'};
|
||||||
|
height: 28px;
|
||||||
|
padding: 0 2px 0 ${({ $depth = 0 }) => `${$depth === 0 ? 4 : 11}px`};
|
||||||
|
position: relative;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background-color 0.14s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: ${({ $active, $interactive }) =>
|
||||||
|
$active || $interactive
|
||||||
|
? VISUAL_TOKENS.background.transparent.medium
|
||||||
|
: 'transparent'};
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SidebarIconSurface = styled.div<{
|
const SidebarIconSurface = styled.div<{
|
||||||
@@ -371,8 +427,8 @@ const SidebarItemText = styled.div`
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SidebarItemLabel = styled.span`
|
const SidebarItemLabel = styled.span<{ $active?: boolean }>`
|
||||||
color: ${COLORS.textSecondary};
|
color: ${({ $active }) => ($active ? COLORS.text : COLORS.textSecondary)};
|
||||||
display: none;
|
display: none;
|
||||||
font-family: ${APP_FONT};
|
font-family: ${APP_FONT};
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
@@ -423,12 +479,43 @@ const SidebarChildStack = styled.div`
|
|||||||
const BranchLine = styled.div`
|
const BranchLine = styled.div`
|
||||||
background: ${COLORS.borderStrong};
|
background: ${COLORS.borderStrong};
|
||||||
bottom: 14px;
|
bottom: 14px;
|
||||||
left: 15px;
|
left: 11px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const SidebarBranchCell = styled.div<{ $isLastChild?: boolean }>`
|
||||||
|
align-self: stretch;
|
||||||
|
position: relative;
|
||||||
|
width: 9px;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
background: ${COLORS.borderStrong};
|
||||||
|
content: '';
|
||||||
|
inset: 0 88.89% 0 0;
|
||||||
|
opacity: ${({ $isLastChild }) => ($isLastChild ? 0 : 1)};
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border-bottom: 1px solid ${COLORS.borderStrong};
|
||||||
|
border-left: 1px solid ${COLORS.borderStrong};
|
||||||
|
border-radius: 0 0 0 4px;
|
||||||
|
content: '';
|
||||||
|
inset: 0 0 45.83% 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SidebarRowMain = styled.div<{ $withBranch?: boolean }>`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
min-width: 0;
|
||||||
|
padding-left: ${({ $withBranch }) => ($withBranch ? '4px' : '0')};
|
||||||
|
`;
|
||||||
|
|
||||||
const SidebarAvatar = styled.div<{
|
const SidebarAvatar = styled.div<{
|
||||||
$background: string;
|
$background: string;
|
||||||
$color: string;
|
$color: string;
|
||||||
@@ -450,9 +537,11 @@ const SidebarAvatar = styled.div<{
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const RightPane = styled.div`
|
const RightPane = styled.div`
|
||||||
display: grid;
|
display: flex;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
flex-direction: column;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
grid-template-rows: 32px minmax(0, 1fr);
|
min-height: 0;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding: 12px 8px 12px 0;
|
padding: 12px 8px 12px 0;
|
||||||
|
|
||||||
@@ -465,6 +554,8 @@ const NavbarBar = styled.div`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex: 0 0 32px;
|
||||||
|
height: 32px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
`;
|
`;
|
||||||
@@ -524,12 +615,13 @@ const DesktopOnlyNavbarAction = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const NavbarDecorativeChip = styled.div`
|
const NAVBAR_ACTION_BORDER = 'rgba(0, 0, 0, 0.08)';
|
||||||
|
|
||||||
|
const NavbarActionButton = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: 1px solid ${VISUAL_TOKENS.background.transparent.medium};
|
border: 1px solid ${NAVBAR_ACTION_BORDER};
|
||||||
border-radius: ${VISUAL_TOKENS.border.radius.sm};
|
border-radius: ${VISUAL_TOKENS.border.radius.sm};
|
||||||
color: ${VISUAL_TOKENS.font.color.secondary};
|
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
font-family: ${APP_FONT};
|
font-family: ${APP_FONT};
|
||||||
font-size: ${VISUAL_TOKENS.font.size.md};
|
font-size: ${VISUAL_TOKENS.font.size.md};
|
||||||
@@ -540,19 +632,38 @@ const NavbarDecorativeChip = styled.div`
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const NavbarDecorativeIconWrap = styled.span`
|
const NavbarActionIconWrap = styled.span<{ $color?: string }>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: currentColor;
|
color: ${({ $color }) => $color ?? VISUAL_TOKENS.font.color.secondary};
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const NavbarActionLabel = styled.span<{ $color?: string }>`
|
||||||
|
color: ${({ $color }) => $color ?? VISUAL_TOKENS.font.color.secondary};
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
line-height: 1.4;
|
||||||
|
white-space: nowrap;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const NavbarActionSeparator = styled.div`
|
||||||
|
background: ${VISUAL_TOKENS.background.transparent.medium};
|
||||||
|
border-radius: 56px;
|
||||||
|
height: 100%;
|
||||||
|
width: 1px;
|
||||||
|
`;
|
||||||
|
|
||||||
const IndexSurface = styled.div`
|
const IndexSurface = styled.div`
|
||||||
background: ${COLORS.background};
|
background: ${COLORS.background};
|
||||||
|
border: 1px solid ${COLORS.border};
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-rows: 40px minmax(0, 1fr);
|
flex: 1 1 auto;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
`;
|
`;
|
||||||
@@ -563,15 +674,19 @@ const ViewbarBar = styled.div`
|
|||||||
border-bottom: 1px solid ${COLORS.borderLight};
|
border-bottom: 1px solid ${COLORS.borderLight};
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
min-width: 0;
|
||||||
padding: 8px 8px 8px 12px;
|
padding: 8px 8px 8px 12px;
|
||||||
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ViewSwitcher = styled.div`
|
const ViewSwitcher = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex: 1 1 auto;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -603,7 +718,11 @@ const TinyDot = styled.div`
|
|||||||
const ViewActions = styled.div`
|
const ViewActions = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
|
margin-left: auto;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ViewAction = styled.span`
|
const ViewAction = styled.span`
|
||||||
@@ -622,7 +741,11 @@ const ViewAction = styled.span`
|
|||||||
|
|
||||||
const TableShell = styled.div`
|
const TableShell = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const GripRail = styled.div`
|
const GripRail = styled.div`
|
||||||
@@ -640,11 +763,14 @@ const GripCell = styled.div`
|
|||||||
|
|
||||||
const TableViewport = styled.div<{ $dragging: boolean }>`
|
const TableViewport = styled.div<{ $dragging: boolean }>`
|
||||||
cursor: ${({ $dragging }) => ($dragging ? 'grabbing' : 'grab')};
|
cursor: ${({ $dragging }) => ($dragging ? 'grabbing' : 'grab')};
|
||||||
|
flex: 1 1 auto;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
min-width: 0;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
overscroll-behavior-x: contain;
|
overscroll-behavior-x: contain;
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -652,6 +778,10 @@ const TableViewport = styled.div<{ $dragging: boolean }>`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const TableCanvas = styled.div<{ $width: number }>`
|
const TableCanvas = styled.div<{ $width: number }>`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 100%;
|
||||||
min-width: ${({ $width }) => `${$width}px`};
|
min-width: ${({ $width }) => `${$width}px`};
|
||||||
width: ${({ $width }) => `${$width}px`};
|
width: ${({ $width }) => `${$width}px`};
|
||||||
`;
|
`;
|
||||||
@@ -693,7 +823,7 @@ const TableCell = styled.div<{
|
|||||||
$align === 'right' ? 'flex-end' : 'flex-start'};
|
$align === 'right' ? 'flex-end' : 'flex-start'};
|
||||||
left: ${({ $sticky }) => ($sticky ? '0' : 'auto')};
|
left: ${({ $sticky }) => ($sticky ? '0' : 'auto')};
|
||||||
min-width: ${({ $width }) => `${$width}px`};
|
min-width: ${({ $width }) => `${$width}px`};
|
||||||
padding: 0 8px;
|
padding: 0 ${TABLE_CELL_HORIZONTAL_PADDING}px;
|
||||||
position: ${({ $sticky }) => ($sticky ? 'sticky' : 'relative')};
|
position: ${({ $sticky }) => ($sticky ? 'sticky' : 'relative')};
|
||||||
z-index: ${({ $header, $sticky }) => {
|
z-index: ${({ $header, $sticky }) => {
|
||||||
if ($sticky && $header) {
|
if ($sticky && $header) {
|
||||||
@@ -778,6 +908,16 @@ const EntityCellLayout = styled.div`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
height: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const CellHoverAnchor = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -826,7 +966,7 @@ const PersonAvatarCircle = styled.div<{
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
font-family: ${APP_FONT};
|
font-family: ${APP_FONT};
|
||||||
font-size: 9px;
|
font-size: 10px;
|
||||||
font-weight: ${theme.font.weight.medium};
|
font-weight: ${theme.font.weight.medium};
|
||||||
height: 14px;
|
height: 14px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -847,24 +987,29 @@ const BooleanRow = styled.div`
|
|||||||
gap: 4px;
|
gap: 4px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const HoverActions = styled.div<{ $visible: boolean }>`
|
const HoverActions = styled.div<{ $rightInset?: number; $visible: boolean }>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: ${COLORS.backgroundSecondary};
|
background: ${VISUAL_TOKENS.background.transparent.primary};
|
||||||
border: 1px solid ${COLORS.border};
|
border: 1px solid ${VISUAL_TOKENS.background.transparent.light};
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
bottom: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
box-shadow: ${VISUAL_TOKENS.boxShadow.light};
|
box-shadow: ${VISUAL_TOKENS.boxShadow.light};
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 2px;
|
gap: 0;
|
||||||
|
justify-content: center;
|
||||||
opacity: ${({ $visible }) => ($visible ? 1 : 0)};
|
opacity: ${({ $visible }) => ($visible ? 1 : 0)};
|
||||||
padding: 2px;
|
padding: 0 4px;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 4px;
|
right: ${({ $rightInset = HOVER_ACTION_EDGE_INSET - TABLE_CELL_HORIZONTAL_PADDING }) =>
|
||||||
|
`${$rightInset}px`};
|
||||||
top: 4px;
|
top: 4px;
|
||||||
transform: translateX(${({ $visible }) => ($visible ? '0' : '4px')});
|
transform: translateX(${({ $visible }) => ($visible ? '0' : '4px')});
|
||||||
transition:
|
transition:
|
||||||
opacity 0.14s ease,
|
opacity 0.14s ease,
|
||||||
transform 0.14s ease;
|
transform 0.14s ease;
|
||||||
|
width: 24px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const MiniAction = styled.div`
|
const MiniAction = styled.div`
|
||||||
@@ -872,9 +1017,9 @@ const MiniAction = styled.div`
|
|||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
color: ${COLORS.textSecondary};
|
color: ${COLORS.textSecondary};
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 20px;
|
height: 16px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 20px;
|
width: 16px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const FooterFirstContent = styled.div`
|
const FooterFirstContent = styled.div`
|
||||||
@@ -960,6 +1105,7 @@ const HEADER_ICON_MAP: Record<string, typeof IconBuildingSkyscraper> = {
|
|||||||
|
|
||||||
// -- Utility functions --
|
// -- Utility functions --
|
||||||
|
|
||||||
|
const failedAvatarUrls = new Set<string>();
|
||||||
const failedFaviconUrls = new Set<string>();
|
const failedFaviconUrls = new Set<string>();
|
||||||
|
|
||||||
function getInitials(value: string) {
|
function getInitials(value: string) {
|
||||||
@@ -1157,15 +1303,17 @@ function CopyMini({ color = COLORS.textSecondary, size = 14 }: MiniIconProps) {
|
|||||||
// -- Favicon logo component --
|
// -- Favicon logo component --
|
||||||
|
|
||||||
function FaviconLogo({
|
function FaviconLogo({
|
||||||
|
src,
|
||||||
domain,
|
domain,
|
||||||
label,
|
label,
|
||||||
size = 14,
|
size = 14,
|
||||||
}: {
|
}: {
|
||||||
|
src?: string;
|
||||||
domain?: string;
|
domain?: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
size?: number;
|
size?: number;
|
||||||
}) {
|
}) {
|
||||||
const faviconUrl = getLogoUrlFromDomainName(domain);
|
const faviconUrl = src ?? getLogoUrlFromDomainName(domain);
|
||||||
const [localFailedUrl, setLocalFailedUrl] = useState<string | null>(null);
|
const [localFailedUrl, setLocalFailedUrl] = useState<string | null>(null);
|
||||||
const showFavicon =
|
const showFavicon =
|
||||||
faviconUrl !== undefined &&
|
faviconUrl !== undefined &&
|
||||||
@@ -1213,6 +1361,31 @@ function FaviconLogo({
|
|||||||
|
|
||||||
// -- Sidebar icon rendering --
|
// -- Sidebar icon rendering --
|
||||||
|
|
||||||
|
function PersonAvatarContent({ token }: { token: HeroCellPerson }) {
|
||||||
|
const [localFailedUrl, setLocalFailedUrl] = useState<string | null>(null);
|
||||||
|
const showAvatar =
|
||||||
|
token.avatarUrl !== undefined &&
|
||||||
|
!failedAvatarUrls.has(token.avatarUrl) &&
|
||||||
|
localFailedUrl !== token.avatarUrl;
|
||||||
|
|
||||||
|
if (showAvatar) {
|
||||||
|
return (
|
||||||
|
<AvatarImage
|
||||||
|
alt=""
|
||||||
|
src={token.avatarUrl}
|
||||||
|
onError={() => {
|
||||||
|
if (token.avatarUrl) {
|
||||||
|
failedAvatarUrls.add(token.avatarUrl);
|
||||||
|
setLocalFailedUrl(token.avatarUrl);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return token.shortLabel ?? getInitials(token.name);
|
||||||
|
}
|
||||||
|
|
||||||
function renderSidebarIcon(icon: HeroSidebarIcon): ReactNode {
|
function renderSidebarIcon(icon: HeroSidebarIcon): ReactNode {
|
||||||
if (icon.kind === 'brand') {
|
if (icon.kind === 'brand') {
|
||||||
return (
|
return (
|
||||||
@@ -1223,14 +1396,16 @@ function renderSidebarIcon(icon: HeroSidebarIcon): ReactNode {
|
|||||||
>
|
>
|
||||||
<FaviconLogo
|
<FaviconLogo
|
||||||
domain={
|
domain={
|
||||||
icon.brand === 'claude'
|
icon.domain ??
|
||||||
|
(icon.brand === 'claude'
|
||||||
? 'claude.ai'
|
? 'claude.ai'
|
||||||
: icon.brand === 'stripe'
|
: icon.brand === 'stripe'
|
||||||
? 'stripe.com'
|
? 'stripe.com'
|
||||||
: undefined
|
: undefined)
|
||||||
}
|
}
|
||||||
label={icon.brand}
|
label={icon.brand}
|
||||||
size={16}
|
size={icon.imageSrc ? 14 : 16}
|
||||||
|
src={icon.imageSrc}
|
||||||
/>
|
/>
|
||||||
{icon.overlay === 'link' ? (
|
{icon.overlay === 'link' ? (
|
||||||
<div
|
<div
|
||||||
@@ -1320,45 +1495,77 @@ function renderSidebarIcon(icon: HeroSidebarIcon): ReactNode {
|
|||||||
function SidebarItemComponent({
|
function SidebarItemComponent({
|
||||||
depth = 0,
|
depth = 0,
|
||||||
interactive = true,
|
interactive = true,
|
||||||
|
isLastChild = false,
|
||||||
item,
|
item,
|
||||||
onSelect,
|
onSelect,
|
||||||
selectedLabel,
|
selectedLabel,
|
||||||
}: {
|
}: {
|
||||||
depth?: number;
|
depth?: number;
|
||||||
interactive?: boolean;
|
interactive?: boolean;
|
||||||
|
isLastChild?: boolean;
|
||||||
item: HeroSidebarItem;
|
item: HeroSidebarItem;
|
||||||
onSelect?: (label: string) => void;
|
onSelect?: (label: string) => void;
|
||||||
selectedLabel?: string;
|
selectedLabel?: string;
|
||||||
}) {
|
}) {
|
||||||
|
const showBranch = depth > 0;
|
||||||
|
const rowSelectable = interactive && item.href === undefined;
|
||||||
|
const rowInteractive = rowSelectable || item.href !== undefined;
|
||||||
const rowActive =
|
const rowActive =
|
||||||
interactive && selectedLabel !== undefined && item.label === selectedLabel;
|
rowSelectable && selectedLabel !== undefined && item.label === selectedLabel;
|
||||||
|
const childItems = item.children ?? [];
|
||||||
|
const rowContent = (
|
||||||
|
<>
|
||||||
|
{showBranch ? <SidebarBranchCell $isLastChild={isLastChild} /> : null}
|
||||||
|
<SidebarRowMain $withBranch={showBranch}>
|
||||||
|
{renderSidebarIcon(item.icon)}
|
||||||
|
<SidebarItemText>
|
||||||
|
<SidebarItemLabel $active={rowActive}>{item.label}</SidebarItemLabel>
|
||||||
|
{item.meta ? <SidebarItemMeta>· {item.meta}</SidebarItemMeta> : null}
|
||||||
|
</SidebarItemText>
|
||||||
|
</SidebarRowMain>
|
||||||
|
{item.showChevron || (item.children && item.children.length > 0) ? (
|
||||||
|
<SidebarChevron>
|
||||||
|
<ChevronDownMini color={COLORS.textTertiary} size={12} />
|
||||||
|
</SidebarChevron>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SidebarItemRow
|
{item.href ? (
|
||||||
$active={rowActive}
|
<SidebarItemRowLink
|
||||||
$depth={depth}
|
$active={rowActive}
|
||||||
onClick={interactive ? () => onSelect?.(item.label) : undefined}
|
$depth={depth}
|
||||||
style={{ cursor: interactive ? 'pointer' : 'default' }}
|
$interactive={rowInteractive}
|
||||||
>
|
$withBranch={showBranch}
|
||||||
{renderSidebarIcon(item.icon)}
|
href={item.href}
|
||||||
<SidebarItemText>
|
rel="noreferrer"
|
||||||
<SidebarItemLabel>{item.label}</SidebarItemLabel>
|
style={{ cursor: rowInteractive ? 'pointer' : 'default' }}
|
||||||
{item.meta ? <SidebarItemMeta>· {item.meta}</SidebarItemMeta> : null}
|
target="_blank"
|
||||||
</SidebarItemText>
|
>
|
||||||
{item.showChevron || (item.children && item.children.length > 0) ? (
|
{rowContent}
|
||||||
<SidebarChevron>
|
</SidebarItemRowLink>
|
||||||
<ChevronDownMini color={COLORS.textTertiary} size={12} />
|
) : (
|
||||||
</SidebarChevron>
|
<SidebarItemRow
|
||||||
) : null}
|
$active={rowActive}
|
||||||
</SidebarItemRow>
|
$depth={depth}
|
||||||
{item.children && item.children.length > 0 ? (
|
$interactive={rowInteractive}
|
||||||
|
$withBranch={showBranch}
|
||||||
|
onClick={rowSelectable ? () => onSelect?.(item.label) : undefined}
|
||||||
|
style={{ cursor: rowInteractive ? 'pointer' : 'default' }}
|
||||||
|
>
|
||||||
|
{rowContent}
|
||||||
|
</SidebarItemRow>
|
||||||
|
)}
|
||||||
|
{childItems.length > 0 ? (
|
||||||
<SidebarChildStack>
|
<SidebarChildStack>
|
||||||
<BranchLine />
|
<BranchLine />
|
||||||
{item.children.map((child) => (
|
{childItems.map((child, index) => (
|
||||||
<SidebarItemComponent
|
<SidebarItemComponent
|
||||||
key={child.id}
|
key={child.id}
|
||||||
depth={depth + 1}
|
depth={depth + 1}
|
||||||
|
isLastChild={index === childItems.length - 1}
|
||||||
interactive={interactive}
|
interactive={interactive}
|
||||||
item={child}
|
item={child}
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
@@ -1389,7 +1596,7 @@ function PersonTokenCell({
|
|||||||
token.kind === 'workflow';
|
token.kind === 'workflow';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ minWidth: 0, position: 'relative', width: '100%' }}>
|
<CellHoverAnchor>
|
||||||
<CellChip
|
<CellChip
|
||||||
clickable={false}
|
clickable={false}
|
||||||
label={token.name}
|
label={token.name}
|
||||||
@@ -1399,11 +1606,7 @@ function PersonTokenCell({
|
|||||||
$color={tone.color}
|
$color={tone.color}
|
||||||
$square={square}
|
$square={square}
|
||||||
>
|
>
|
||||||
{token.avatarUrl ? (
|
<PersonAvatarContent token={token} />
|
||||||
<AvatarImage alt="" src={token.avatarUrl} />
|
|
||||||
) : (
|
|
||||||
(token.shortLabel ?? getInitials(token.name))
|
|
||||||
)}
|
|
||||||
</PersonAvatarCircle>
|
</PersonAvatarCircle>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -1413,11 +1616,8 @@ function PersonTokenCell({
|
|||||||
<CopyMini />
|
<CopyMini />
|
||||||
</MiniAction>
|
</MiniAction>
|
||||||
) : null}
|
) : null}
|
||||||
<MiniAction aria-hidden="true">
|
|
||||||
<PencilMini />
|
|
||||||
</MiniAction>
|
|
||||||
</HoverActions>
|
</HoverActions>
|
||||||
</div>
|
</CellHoverAnchor>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1468,7 +1668,7 @@ function RelationCellComponent({
|
|||||||
hovered: boolean;
|
hovered: boolean;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div style={{ minWidth: 0, position: 'relative', width: '100%' }}>
|
<CellHoverAnchor>
|
||||||
<MultiChipStack>
|
<MultiChipStack>
|
||||||
{cell.items.map((item) => {
|
{cell.items.map((item) => {
|
||||||
const tone = PERSON_TONES[item.tone ?? 'gray'] ?? PERSON_TONES.gray;
|
const tone = PERSON_TONES[item.tone ?? 'gray'] ?? PERSON_TONES.gray;
|
||||||
@@ -1494,11 +1694,37 @@ function RelationCellComponent({
|
|||||||
<MiniAction aria-hidden="true">
|
<MiniAction aria-hidden="true">
|
||||||
<CopyMini />
|
<CopyMini />
|
||||||
</MiniAction>
|
</MiniAction>
|
||||||
<MiniAction aria-hidden="true">
|
|
||||||
<PencilMini />
|
|
||||||
</MiniAction>
|
|
||||||
</HoverActions>
|
</HoverActions>
|
||||||
</div>
|
</CellHoverAnchor>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TextCellComponent({
|
||||||
|
cell,
|
||||||
|
isFirstColumn,
|
||||||
|
}: {
|
||||||
|
cell: HeroCellText;
|
||||||
|
isFirstColumn: boolean;
|
||||||
|
}) {
|
||||||
|
if (!isFirstColumn || !cell.shortLabel) {
|
||||||
|
return <InlineText>{cell.value}</InlineText>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tone = PERSON_TONES[cell.tone ?? 'gray'] ?? PERSON_TONES.gray;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CellChip
|
||||||
|
clickable={false}
|
||||||
|
label={cell.value}
|
||||||
|
leftComponent={
|
||||||
|
<PersonAvatarCircle
|
||||||
|
$background={tone.background}
|
||||||
|
$color={tone.color}
|
||||||
|
>
|
||||||
|
{cell.shortLabel}
|
||||||
|
</PersonAvatarCircle>
|
||||||
|
}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1506,10 +1732,13 @@ function renderCellValue(
|
|||||||
cell: HeroCellValue,
|
cell: HeroCellValue,
|
||||||
hovered: boolean,
|
hovered: boolean,
|
||||||
isFirstColumn: boolean,
|
isFirstColumn: boolean,
|
||||||
|
columnId: string,
|
||||||
): ReactNode {
|
): ReactNode {
|
||||||
|
const showHoverAction = !ROW_HOVER_ACTION_DISABLED_COLUMNS.has(columnId);
|
||||||
|
|
||||||
switch (cell.type) {
|
switch (cell.type) {
|
||||||
case 'text':
|
case 'text':
|
||||||
return <InlineText>{cell.value}</InlineText>;
|
return <TextCellComponent cell={cell} isFirstColumn={isFirstColumn} />;
|
||||||
case 'number':
|
case 'number':
|
||||||
return <RightAlignedText>{cell.value}</RightAlignedText>;
|
return <RightAlignedText>{cell.value}</RightAlignedText>;
|
||||||
case 'link':
|
case 'link':
|
||||||
@@ -1520,11 +1749,6 @@ function renderCellValue(
|
|||||||
label={cell.value}
|
label={cell.value}
|
||||||
variant={ChipVariant.Static}
|
variant={ChipVariant.Static}
|
||||||
/>
|
/>
|
||||||
<HoverActions $visible={hovered}>
|
|
||||||
<MiniAction aria-hidden="true">
|
|
||||||
<PencilMini />
|
|
||||||
</MiniAction>
|
|
||||||
</HoverActions>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
@@ -1537,17 +1761,24 @@ function renderCellValue(
|
|||||||
case 'tag':
|
case 'tag':
|
||||||
return <TagChip>{cell.value}</TagChip>;
|
return <TagChip>{cell.value}</TagChip>;
|
||||||
case 'person':
|
case 'person':
|
||||||
return <PersonTokenCell hovered={hovered} token={cell} />;
|
return (
|
||||||
|
<PersonTokenCell hovered={hovered && showHoverAction} token={cell} />
|
||||||
|
);
|
||||||
case 'entity':
|
case 'entity':
|
||||||
return (
|
return (
|
||||||
<EntityCellComponent
|
<EntityCellComponent
|
||||||
cell={cell}
|
cell={cell}
|
||||||
hovered={hovered}
|
hovered={hovered && showHoverAction}
|
||||||
isFirstColumn={isFirstColumn}
|
isFirstColumn={isFirstColumn}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'relation':
|
case 'relation':
|
||||||
return <RelationCellComponent cell={cell} hovered={hovered} />;
|
return (
|
||||||
|
<RelationCellComponent
|
||||||
|
cell={cell}
|
||||||
|
hovered={hovered && showHoverAction}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1728,11 +1959,10 @@ export function HomeVisual({ visual }: { visual: HeroVisualType }) {
|
|||||||
<SidebarTopBar>
|
<SidebarTopBar>
|
||||||
<WorkspaceMenu>
|
<WorkspaceMenu>
|
||||||
<WorkspaceIcon>
|
<WorkspaceIcon>
|
||||||
<IconBrandApple
|
<WorkspaceIconImage
|
||||||
aria-hidden
|
alt=""
|
||||||
color="#ffffff"
|
aria-hidden="true"
|
||||||
size={11}
|
src={APPLE_WORKSPACE_LOGO_SRC}
|
||||||
stroke={2}
|
|
||||||
/>
|
/>
|
||||||
</WorkspaceIcon>
|
</WorkspaceIcon>
|
||||||
<WorkspaceLabel>{visual.workspace.name}</WorkspaceLabel>
|
<WorkspaceLabel>{visual.workspace.name}</WorkspaceLabel>
|
||||||
@@ -1777,7 +2007,7 @@ export function HomeVisual({ visual }: { visual: HeroVisualType }) {
|
|||||||
</SidebarSection>
|
</SidebarSection>
|
||||||
) : null}
|
) : null}
|
||||||
<SidebarSection>
|
<SidebarSection>
|
||||||
<SidebarSectionLabel>Workspace</SidebarSectionLabel>
|
<SidebarSectionLabel $workspace>Workspace</SidebarSectionLabel>
|
||||||
{visual.workspaceNav.map(renderSidebarEntry)}
|
{visual.workspaceNav.map(renderSidebarEntry)}
|
||||||
</SidebarSection>
|
</SidebarSection>
|
||||||
</SidebarScroll>
|
</SidebarScroll>
|
||||||
@@ -1800,26 +2030,30 @@ export function HomeVisual({ visual }: { visual: HeroVisualType }) {
|
|||||||
|
|
||||||
<NavbarActions aria-hidden>
|
<NavbarActions aria-hidden>
|
||||||
<DesktopOnlyNavbarAction>
|
<DesktopOnlyNavbarAction>
|
||||||
<NavbarDecorativeChip>
|
<NavbarActionButton>
|
||||||
<NavbarDecorativeIconWrap>
|
<NavbarActionIconWrap>
|
||||||
<IconPlus
|
<IconPlus
|
||||||
aria-hidden
|
aria-hidden
|
||||||
size={VISUAL_TOKENS.icon.size.sm}
|
size={VISUAL_TOKENS.icon.size.sm}
|
||||||
stroke={VISUAL_TOKENS.icon.stroke.sm}
|
stroke={VISUAL_TOKENS.icon.stroke.sm}
|
||||||
/>
|
/>
|
||||||
</NavbarDecorativeIconWrap>
|
</NavbarActionIconWrap>
|
||||||
New Record
|
<NavbarActionLabel>New Record</NavbarActionLabel>
|
||||||
</NavbarDecorativeChip>
|
</NavbarActionButton>
|
||||||
</DesktopOnlyNavbarAction>
|
</DesktopOnlyNavbarAction>
|
||||||
<NavbarDecorativeChip>
|
<NavbarActionButton>
|
||||||
<NavbarDecorativeIconWrap>
|
<NavbarActionIconWrap>
|
||||||
<IconDotsVertical
|
<IconDotsVertical
|
||||||
aria-hidden
|
aria-hidden
|
||||||
size={VISUAL_TOKENS.icon.size.sm}
|
size={VISUAL_TOKENS.icon.size.sm}
|
||||||
stroke={VISUAL_TOKENS.icon.stroke.sm}
|
stroke={VISUAL_TOKENS.icon.stroke.sm}
|
||||||
/>
|
/>
|
||||||
</NavbarDecorativeIconWrap>
|
</NavbarActionIconWrap>
|
||||||
</NavbarDecorativeChip>
|
<NavbarActionSeparator />
|
||||||
|
<NavbarActionLabel $color={VISUAL_TOKENS.font.color.light}>
|
||||||
|
⌘K
|
||||||
|
</NavbarActionLabel>
|
||||||
|
</NavbarActionButton>
|
||||||
</NavbarActions>
|
</NavbarActions>
|
||||||
</NavbarBar>
|
</NavbarBar>
|
||||||
|
|
||||||
@@ -1930,6 +2164,7 @@ export function HomeVisual({ visual }: { visual: HeroVisualType }) {
|
|||||||
cell,
|
cell,
|
||||||
hovered,
|
hovered,
|
||||||
!!column.isFirstColumn,
|
!!column.isFirstColumn,
|
||||||
|
column.id,
|
||||||
)
|
)
|
||||||
: null}
|
: null}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
+8
-3
@@ -25,7 +25,7 @@ const StyledContainer = styled.div<
|
|||||||
Pick<ChipProps, 'clickable' | 'isBold' | 'maxWidth' | 'variant'>
|
Pick<ChipProps, 'clickable' | 'isBold' | 'maxWidth' | 'variant'>
|
||||||
>`
|
>`
|
||||||
--chip-horizontal-padding: ${VISUAL_TOKENS.spacing[1]};
|
--chip-horizontal-padding: ${VISUAL_TOKENS.spacing[1]};
|
||||||
--chip-vertical-padding: ${VISUAL_TOKENS.spacing[1]};
|
--chip-vertical-padding: 3px;
|
||||||
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: ${({ variant }) =>
|
background-color: ${({ variant }) =>
|
||||||
@@ -70,6 +70,9 @@ const StyledContainer = styled.div<
|
|||||||
? VISUAL_TOKENS.spacing[2]
|
? VISUAL_TOKENS.spacing[2]
|
||||||
: 'var(--chip-horizontal-padding)'};
|
: 'var(--chip-horizontal-padding)'};
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
font-family: ${VISUAL_TOKENS.font.family};
|
||||||
|
font-size: ${VISUAL_TOKENS.font.size.md};
|
||||||
|
line-height: 1.4;
|
||||||
|
|
||||||
font-weight: ${({ isBold }) =>
|
font-weight: ${({ isBold }) =>
|
||||||
isBold
|
isBold
|
||||||
@@ -83,7 +86,7 @@ const StyledContainer = styled.div<
|
|||||||
: variant === ChipVariant.Highlighted
|
: variant === ChipVariant.Highlighted
|
||||||
? VISUAL_TOKENS.background.transparent.medium
|
? VISUAL_TOKENS.background.transparent.medium
|
||||||
: variant === ChipVariant.Static
|
: variant === ChipVariant.Static
|
||||||
? VISUAL_TOKENS.background.transparent.light
|
? VISUAL_TOKENS.background.transparent.lighter
|
||||||
: 'inherit'};
|
: 'inherit'};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +97,7 @@ const StyledContainer = styled.div<
|
|||||||
: variant === ChipVariant.Highlighted
|
: variant === ChipVariant.Highlighted
|
||||||
? VISUAL_TOKENS.background.transparent.strong
|
? VISUAL_TOKENS.background.transparent.strong
|
||||||
: variant === ChipVariant.Static
|
: variant === ChipVariant.Static
|
||||||
? VISUAL_TOKENS.background.transparent.light
|
? VISUAL_TOKENS.background.transparent.lighter
|
||||||
: 'inherit'};
|
: 'inherit'};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,8 +108,10 @@ const StyledContainer = styled.div<
|
|||||||
|
|
||||||
const StyledLabel = styled.span`
|
const StyledLabel = styled.span`
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
font-family: inherit;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
font-weight: inherit;
|
font-weight: inherit;
|
||||||
|
line-height: inherit;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
+1
-2
@@ -35,8 +35,7 @@ export const VISUAL_TOKENS = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
background: {
|
background: {
|
||||||
noisy:
|
noisy: 'url("/images/shared/light-noise.png")',
|
||||||
"url(\"data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.5' numOctaves='6' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)' opacity='0.03'/%3E%3C/svg%3E\")",
|
|
||||||
primary: '#ffffff',
|
primary: '#ffffff',
|
||||||
secondary: '#fcfcfc',
|
secondary: '#fcfcfc',
|
||||||
transparent: {
|
transparent: {
|
||||||
|
|||||||
@@ -2,7 +2,12 @@ import type { HeroBaseDataType } from '@/sections/Hero/types/HeroBaseData';
|
|||||||
|
|
||||||
// -- Cell value types --
|
// -- Cell value types --
|
||||||
|
|
||||||
export type HeroCellText = { type: 'text'; value: string };
|
export type HeroCellText = {
|
||||||
|
type: 'text';
|
||||||
|
value: string;
|
||||||
|
shortLabel?: string;
|
||||||
|
tone?: string;
|
||||||
|
};
|
||||||
export type HeroCellNumber = { type: 'number'; value: string };
|
export type HeroCellNumber = { type: 'number'; value: string };
|
||||||
export type HeroCellLink = { type: 'link'; value: string };
|
export type HeroCellLink = { type: 'link'; value: string };
|
||||||
export type HeroCellBoolean = { type: 'boolean'; value: boolean };
|
export type HeroCellBoolean = { type: 'boolean'; value: boolean };
|
||||||
@@ -57,7 +62,13 @@ export type HeroRowDef = {
|
|||||||
|
|
||||||
export type HeroSidebarIcon =
|
export type HeroSidebarIcon =
|
||||||
| { kind: 'tabler'; name: string; tone: string; overlay?: 'link' }
|
| { kind: 'tabler'; name: string; tone: string; overlay?: 'link' }
|
||||||
| { kind: 'brand'; brand: string; overlay?: 'link' }
|
| {
|
||||||
|
kind: 'brand';
|
||||||
|
brand: string;
|
||||||
|
domain?: string;
|
||||||
|
imageSrc?: string;
|
||||||
|
overlay?: 'link';
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
kind: 'avatar';
|
kind: 'avatar';
|
||||||
label: string;
|
label: string;
|
||||||
@@ -70,6 +81,7 @@ export type HeroSidebarIcon =
|
|||||||
export type HeroSidebarItem = {
|
export type HeroSidebarItem = {
|
||||||
id: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
|
href?: string;
|
||||||
icon: HeroSidebarIcon;
|
icon: HeroSidebarIcon;
|
||||||
meta?: string;
|
meta?: string;
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user