Skip to content

Commit 3268a69

Browse files
committed
refactor: redesign landing hero
1 parent 2e72f45 commit 3268a69

20 files changed

Lines changed: 736 additions & 534 deletions

apps/showcase/app/(app)/(landing)/components/cards/add-member.tsx

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
'use client';
2-
import { ChevronDown, Copy, Times } from '@primeicons/react';
2+
import { ChevronDown, Link, Times } from '@primeicons/react';
33
import { Avatar } from '@primereact/ui/avatar';
44
import { Button } from '@primereact/ui/button';
5-
import { Divider } from '@primereact/ui/divider';
5+
import { IconField } from '@primereact/ui/iconfield';
66
import { InputGroup } from '@primereact/ui/inputgroup';
77
import { InputText } from '@primereact/ui/inputtext';
88
import { Select } from '@primereact/ui/select';
@@ -24,13 +24,13 @@ const members = [
2424

2525
export function AddMemberCard({ className, ...props }: React.ComponentProps<'div'>) {
2626
return (
27-
<div className={cn('relative p-1.5 rounded-[18px] bg-surface-100 dark:bg-surface-800/60 shadow-[0_0_0_0.5px_rgba(0,0,0,0.2)] dark:shadow-[0_0_0_0.5px_rgba(255,255,255,0.2)]', className)} {...props}>
28-
<div className="flex flex-col gap-4 p-6 bg-surface-0 dark:bg-surface-950/50 rounded-xl shadow-[0_0_0_0.5px_rgba(0,0,0,0.15)] dark:shadow-[0_0_0_0.5px_rgba(255,255,255,0.15)] overflow-auto w-full h-full">
27+
<div className={cn('relative', className)}>
28+
<div className="flex flex-col gap-3 p-6 bg-surface-0 dark:bg-surface-950/50 rounded-xl shadow-[0_0_0_0.5px_rgba(0,0,0,0.15)] dark:shadow-[0_0_0_0.5px_rgba(255,255,255,0.15)] overflow-auto w-full h-full" {...props}>
2929
{/* Header */}
3030
<div className="flex items-start justify-between gap-2">
3131
<div>
32-
<div className="text-base font-bold text-color">Share project</div>
33-
<div className="text-sm text-muted-color mt-1">Manage who has access to this project.</div>
32+
<div className="text-lg font-bold text-color">Share project</div>
33+
<div className="text-muted-color">Manage who has access to this project.</div>
3434
</div>
3535
<Button iconOnly variant="text" severity="secondary" size="small" className="absolute top-5 right-5">
3636
<Times className="size-4!" />
@@ -47,11 +47,11 @@ export function AddMemberCard({ className, ...props }: React.ComponentProps<'div
4747
</ToggleButtonGroup>
4848

4949
{/* Direct link */}
50-
<div className="p-3 rounded-lg bg-surface-100 dark:bg-surface-800">
50+
<div className="px-4 py-3.5 rounded-lg bg-surface-100 dark:bg-surface-800/50 border border-surface-200 dark:border-surface-800">
5151
<div className="flex items-start justify-between mb-2">
5252
<div>
53-
<div className="text-sm font-semibold text-color">Direct link</div>
54-
<div className="text-sm text-muted-color">Anyone with the link can access</div>
53+
<div className="font-semibold text-color">Direct link</div>
54+
<div className="text-muted-color">Anyone with the link can access</div>
5555
</div>
5656
<Select.Root size="small" defaultValue="view" options={accessOptions} optionLabel="label" optionValue="value">
5757
<Select.Trigger>
@@ -71,54 +71,57 @@ export function AddMemberCard({ className, ...props }: React.ComponentProps<'div
7171
</div>
7272
<div className="flex items-center gap-2 mt-2">
7373
<InputGroup.Root>
74-
<InputText defaultValue="https://acme.com/project/abc123" readOnly />
74+
<IconField.Root>
75+
<IconField.Inset>
76+
<Link className="size-3.5! text-surface-500!" />
77+
</IconField.Inset>
78+
<InputText defaultValue="https://acme.com/project/abc123" readOnly />
79+
</IconField.Root>
7580
<InputGroup.Addon>
76-
<Button severity="secondary" variant="text" iconOnly>
77-
<Copy />
81+
<Button variant="text" severity="secondary" className="px-4 font-semibold">
82+
Copy
7883
</Button>
7984
</InputGroup.Addon>
8085
</InputGroup.Root>
8186
</div>
8287
</div>
8388

84-
<Divider.Root className="-my-1" />
85-
{/* Invite */}
86-
<div>
87-
<div className="text-sm font-medium text-color">Invite to collaborate</div>
88-
<div className="flex items-center gap-2 mt-2">
89-
<InputText className="flex-1" placeholder="Email or username" />
90-
<Button>Invite</Button>
89+
<div className="mt-2">
90+
<div>
91+
<div className="font-semibold text-color">Invite to collaborate</div>
92+
<div className="flex items-center gap-2 mt-2">
93+
<InputText className="flex-1" placeholder="Email or username" />
94+
<Button>Invite</Button>
95+
</div>
9196
</div>
92-
</div>
9397

94-
{/* Members */}
95-
<div className="flex flex-col gap-3">
96-
{members.map((member) => (
97-
<div key={member.email} className="flex items-center gap-2">
98-
<Avatar.Root className="w-8 h-8" shape="circle">
99-
<Avatar.Image src={member.avatar} />
100-
</Avatar.Root>
101-
<div className="flex-1 min-w-0">
102-
<div className="text-sm font-medium text-color">{member.name}</div>
103-
<div className="text-xs text-muted-color truncate">{member.email}</div>
98+
<div className="flex flex-col gap-4 mt-4">
99+
{members.map((member) => (
100+
<div key={member.email} className="flex items-center gap-2">
101+
<Avatar.Root className="size-6" shape="circle">
102+
<Avatar.Image src={member.avatar} />
103+
</Avatar.Root>
104+
<div className="flex-1 min-w-0">
105+
<div className="font-medium text-muted-color">{member.name}</div>
106+
</div>
107+
<Select.Root size="small" defaultValue={member.role === 'Can edit' ? 'edit' : 'view'} options={accessOptions} optionLabel="label" optionValue="value">
108+
<Select.Trigger>
109+
<Select.Value />
110+
<Select.Indicator>
111+
<ChevronDown className="size-3!" />
112+
</Select.Indicator>
113+
</Select.Trigger>
114+
<Select.Portal>
115+
<Select.Positioner>
116+
<Select.Popup>
117+
<Select.List />
118+
</Select.Popup>
119+
</Select.Positioner>
120+
</Select.Portal>
121+
</Select.Root>
104122
</div>
105-
<Select.Root size="small" defaultValue={member.role === 'Can edit' ? 'edit' : 'view'} options={accessOptions} optionLabel="label" optionValue="value">
106-
<Select.Trigger>
107-
<Select.Value />
108-
<Select.Indicator>
109-
<ChevronDown className="size-3!" />
110-
</Select.Indicator>
111-
</Select.Trigger>
112-
<Select.Portal>
113-
<Select.Positioner>
114-
<Select.Popup>
115-
<Select.List />
116-
</Select.Popup>
117-
</Select.Positioner>
118-
</Select.Portal>
119-
</Select.Root>
120-
</div>
121-
))}
123+
))}
124+
</div>
122125
</div>
123126
</div>
124127
</div>
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
'use client';
2+
import { ArrowCircleUp, At, Check, ChevronDown, ChevronRight, Clone, Globe, Image, Refresh, ThumbsDown, ThumbsUp } from '@primeicons/react';
3+
import { Button } from '@primereact/ui/button';
4+
import { InputText } from '@primereact/ui/inputtext';
5+
import { MeterGroup } from '@primereact/ui/metergroup';
6+
import { Select, type SelectValueChangeEvent } from '@primereact/ui/select';
7+
import { cn } from '@primeuix/utils';
8+
import * as React from 'react';
9+
10+
const aiModels = [
11+
{ label: 'Claude Opus', value: 'claude-opus' },
12+
{ label: 'Claude Sonnet', value: 'claude-sonnet' },
13+
{ label: 'Claude Haiku', value: 'claude-haiku' },
14+
{ label: 'GPT-4o', value: 'gpt-4o' },
15+
{ label: 'Gemini Pro', value: 'gemini-pro' }
16+
];
17+
18+
export function AiChatCard({ className, ...props }: React.ComponentProps<'div'>) {
19+
const [model, setModel] = React.useState('claude-opus');
20+
const [inputValue, setInputValue] = React.useState('');
21+
22+
return (
23+
<div className={cn('relative', className)} {...props}>
24+
<div className="flex flex-col bg-surface-0 dark:bg-surface-950/50 rounded-xl shadow-[0_0_0_0.5px_rgba(0,0,0,0.15)] dark:shadow-[0_0_0_0.5px_rgba(255,255,255,0.15)] overflow-hidden w-full h-full">
25+
<div className="flex items-center gap-2.5 px-5 py-3.5 ">
26+
<ChevronDown className="size-4! text-surface-500" />
27+
<span className="text-sm font-medium text-surface-500">Storage usage breakdown</span>
28+
</div>
29+
30+
<div className="flex-1 px-6 pt-3 pb-8 overflow-auto">
31+
<div className="max-w-[85%] ml-auto bg-surface-100 dark:bg-surface-950 px-3.5 py-2.5 rounded-xl text-surface-600 dark:text-surface-300 leading-snug font-medium">Show my disk usage as a meter</div>
32+
33+
<div className="flex flex-col gap-3 mt-4">
34+
<div className="text-surface-900 dark:text-surface-100 leading-snug">
35+
<p className="mb-2">
36+
Here&apos;s a <code>MeterGroup</code> breakdown:
37+
</p>
38+
39+
<ul className="flex flex-col gap-1 text-surface-600 dark:text-surface-400">
40+
<li className="flex items-center gap-2">
41+
<Check className="size-3! text-primary shrink-0" />
42+
Color-coded segments
43+
</li>
44+
<li className="flex items-center gap-2">
45+
<Check className="size-3! text-primary shrink-0" />
46+
Labeled categories
47+
</li>
48+
</ul>
49+
</div>
50+
51+
<div className="bg-surface-100 dark:bg-surface-900 border border-surface-200 dark:border-surface-800 rounded-xl py-3 px-4">
52+
<div className="uppercase text-surface-500 font-medium tracking-wider text-xs mb-2">disk usage</div>
53+
<MeterGroup.Root>
54+
<MeterGroup.Meters className="flex rounded-full overflow-hidden bg-surface-200 dark:bg-surface-700">
55+
<MeterGroup.Meter value={25} index={0} className="bg-primary" />
56+
<MeterGroup.Meter value={15} index={1} className="bg-orange-500" />
57+
<MeterGroup.Meter value={20} index={2} className="bg-cyan-500" />
58+
</MeterGroup.Meters>
59+
<MeterGroup.Labels className="flex items-center gap-4 mt-1">
60+
<MeterGroup.Label className="flex items-center gap-1.5 text-xs">
61+
<MeterGroup.Marker index={0} className="size-2 rounded-full bg-primary" />
62+
<MeterGroup.Text className="text-surface-600 dark:text-surface-400">Apps 25%</MeterGroup.Text>
63+
</MeterGroup.Label>
64+
<MeterGroup.Label className="flex items-center gap-1.5 text-xs">
65+
<MeterGroup.Marker index={1} className="size-2 rounded-full bg-orange-500" />
66+
<MeterGroup.Text className="text-surface-600 dark:text-surface-400">Media 15%</MeterGroup.Text>
67+
</MeterGroup.Label>
68+
<MeterGroup.Label className="flex items-center gap-1.5 text-xs">
69+
<MeterGroup.Marker index={2} className="size-2 rounded-full bg-cyan-500" />
70+
<MeterGroup.Text className="text-surface-600 dark:text-surface-400">System 20%</MeterGroup.Text>
71+
</MeterGroup.Label>
72+
</MeterGroup.Labels>
73+
</MeterGroup.Root>
74+
</div>
75+
<div className="flex items-center gap-0.5">
76+
<Button iconOnly variant="text" size="small" severity="secondary">
77+
<Clone className="size-4! text-surface-500" />
78+
</Button>
79+
<Button iconOnly variant="text" size="small" severity="secondary">
80+
<ThumbsUp className="size-4! text-surface-500" />
81+
</Button>
82+
<Button iconOnly variant="text" size="small" severity="secondary">
83+
<ThumbsDown className="size-4! text-surface-500" />
84+
</Button>
85+
<Button iconOnly variant="text" size="small" severity="secondary">
86+
<Refresh className="size-4! text-surface-500" />
87+
</Button>
88+
</div>
89+
</div>
90+
</div>
91+
92+
<div className="px-3.5 pb-3.5">
93+
<div className="relative z-10 rounded-xl bg-surface-50 dark:bg-surface-900 border border-surface-200 dark:border-surface-800 px-3 py-2.5">
94+
<div className="top-0 -z-1 -translate-y-full absolute left-1/2 -translate-x-1/2 bg-surface-100 dark:bg-surface-800/50 p-1 pl-1.5 rounded-t-[10px] flex items-center gap-1 w-11/12 border border-surface-200 dark:border-surface-800">
95+
<ChevronRight className="text-surface-500" />
96+
<div className="flex-1 text-sm text-surface-500 dark:text-surface-400">1 File</div>
97+
<Button size="small" className="py-0.25 px-1 bg-surface-200 dark:bg-surface-800" severity="secondary">
98+
Review
99+
</Button>
100+
</div>
101+
<InputText placeholder="Plan, @ for context, / for commands ..." unstyled className="w-full outline-none" value={inputValue} onChange={(e: React.ChangeEvent<HTMLInputElement>) => setInputValue(e.target.value)} />
102+
<div className="flex items-center gap-1 mt-4">
103+
<div className="flex items-center ">
104+
<Select.Root
105+
className="bg-surface-100 dark:bg-surface-800 border-none! rounded-full w-full h-7 md:w-32 hover:bg-surface-200! dark:hover:bg-surface-800! shadow-none"
106+
size="small"
107+
value={model}
108+
onValueChange={(e: SelectValueChangeEvent) => setModel(e.value as string)}
109+
options={aiModels}
110+
optionLabel="label"
111+
optionValue="value"
112+
>
113+
<Select.Trigger>
114+
<Select.Value placeholder="Select a language" className="text-surface-500 dark:text-surface-400 font-medium" />
115+
<Select.Indicator>
116+
<ChevronDown />
117+
</Select.Indicator>
118+
</Select.Trigger>
119+
120+
<Select.Portal>
121+
<Select.Positioner>
122+
<Select.Popup>
123+
<Select.List />
124+
</Select.Popup>
125+
</Select.Positioner>
126+
</Select.Portal>
127+
</Select.Root>
128+
</div>
129+
<div className="flex-1 flex items-center justify-end gap-1">
130+
<Button iconOnly size="small" className="size-6.5" rounded variant="text" severity="secondary">
131+
<At className="size-4.5!" />
132+
</Button>
133+
<Button iconOnly size="small" className="size-6.5" rounded variant="text" severity="secondary">
134+
<Globe className="size-4.5!" />
135+
</Button>
136+
<Button iconOnly size="small" className="size-6.5" rounded variant="text" severity="secondary">
137+
<Image className="size-4.5!" />
138+
</Button>
139+
<Button iconOnly size="small" className="size-6.5" rounded>
140+
<ArrowCircleUp className="size-4.5! " />
141+
</Button>
142+
</div>
143+
</div>
144+
</div>
145+
</div>
146+
</div>
147+
</div>
148+
);
149+
}

0 commit comments

Comments
 (0)