Skip to content

Commit 290b442

Browse files
committed
feat(ui): add Tabs Checkbox component, update ShareModal styles
1 parent b95b369 commit 290b442

File tree

10 files changed

+148
-4
lines changed

10 files changed

+148
-4
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@
2727
"@solid-primitives/scheduled": "^1.3.2",
2828
"@solid-primitives/scroll": "^2.0.14",
2929
"@unocss/reset": "^0.50.6",
30+
"@zag-js/checkbox": "^0.9.2",
3031
"@zag-js/dialog": "^0.9.2",
3132
"@zag-js/menu": "^0.9.2",
3233
"@zag-js/select": "^0.9.2",
3334
"@zag-js/slider": "^0.9.2",
3435
"@zag-js/solid": "^0.9.2",
3536
"@zag-js/switch": "^0.9.2",
37+
"@zag-js/tabs": "^0.9.2",
3638
"@zag-js/toast": "^0.9.2",
3739
"@zag-js/toggle": "^0.9.2",
3840
"@zag-js/tooltip": "^0.9.2",

pnpm-lock.yaml

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/ModalsLayer.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import {
33
showConversationSidebar,
44
showEmojiPickerModal,
55
showSettingsSidebar,
6+
showShareModal,
67
} from '@/stores/ui'
78
import ConversationSidebar from './conversations/ConversationSidebar'
89
import SettingsSidebar from './settings/SettingsSidebar'
910
import ConversationEditModal from './conversations/ConversationEditModal'
1011
import EmojiPickerModal from './ui/EmojiPickerModal'
12+
import ShareModal from './ui/ShareModal'
1113
import Modal from './ui/Modal'
1214

1315
export default () => {
@@ -33,6 +35,11 @@ export default () => {
3335
<EmojiPickerModal />
3436
</div>
3537
</Modal>
38+
<Modal bindValue={showShareModal} direction="bottom" closeBtnClass="hidden">
39+
<div class="max-h-[70vh] w-full">
40+
<ShareModal />
41+
</div>
42+
</Modal>
3643
</>
3744
)
3845
}

src/components/header/ConversationMessageShareButton.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
import { useStore } from '@nanostores/solid'
22
import { currentConversationId } from '@/stores/conversation'
3+
import { showShareModal } from '@/stores/ui'
34

45
export default () => {
56
const $currentConversationId = useStore(currentConversationId)
67

7-
const handleClearMessage = () => {
8-
}
9-
108
return (
119
<>
1210
{$currentConversationId() && (
1311
<div
1412
class="fcc p-2 rounded-md text-xl hv-foreground"
15-
onClick={handleClearMessage}
13+
onClick={() => { showShareModal.set(true) }}
1614
>
1715
<div i-carbon-export />
1816
</div>

src/components/ui/ShareModal.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { useI18n } from '@/hooks'
2+
import { Tabs } from '../ui/base'
3+
import type { TabItem } from './base/Tabs'
4+
5+
export default () => {
6+
const { t } = useI18n()
7+
8+
const tabs: TabItem[] = [
9+
{
10+
value: 'context',
11+
label: t('conversations.share.tabs.context'),
12+
content: <div class="flex">context</div>,
13+
},
14+
{
15+
value: 'image',
16+
label: t('conversations.share.tabs.image'),
17+
content: <div class="flex">image</div>,
18+
},
19+
]
20+
21+
return (
22+
<div class="w-full">
23+
<div class="fi justify-between border-base b-b-1 px-6 py-4">
24+
<div class="text-base">{t('conversations.share.link.title')}</div>
25+
<button class="emerald-button mt-0">{t('conversations.share.link.create')}</button>
26+
</div>
27+
<div class="fcc flex-col space-y-2 p-6">
28+
<div class="border w-full border-base fi justify-between box-border p-4 rounded-md hv-base">
29+
<span class="text-xs">{t('conversations.share.messages.selected')}</span>
30+
<span class="text-xs op-60">2 Messages</span>
31+
</div>
32+
<Tabs tabs={tabs} />
33+
</div>
34+
</div>
35+
)
36+
}

src/components/ui/base/Checkbox.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import * as checkbox from '@zag-js/checkbox'
2+
import { normalizeProps, useMachine } from '@zag-js/solid'
3+
import { createMemo, createUniqueId } from 'solid-js'
4+
5+
interface Props {
6+
initValue?: boolean
7+
label: string
8+
}
9+
10+
export const Checkbox = (props: Props) => {
11+
const [state, send] = useMachine(checkbox.machine({ id: createUniqueId(), checked: props.initValue ?? false }))
12+
13+
const api = createMemo(() => checkbox.connect(state, send, normalizeProps))
14+
15+
return (
16+
<label {...api().rootProps}>
17+
<span {...api().labelProps}>
18+
{props.label}
19+
</span>
20+
<input {...api().inputProps} />
21+
<div {...api().controlProps} />
22+
</label>
23+
)
24+
}

src/components/ui/base/Tabs.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import * as tabs from '@zag-js/tabs'
2+
import { normalizeProps, useMachine } from '@zag-js/solid'
3+
import { For, createMemo, createUniqueId } from 'solid-js'
4+
import type { JSX } from 'solid-js'
5+
6+
export interface TabItem {
7+
value: string
8+
label: string
9+
content: JSX.Element
10+
}
11+
12+
interface Props {
13+
tabs: TabItem[]
14+
initValue?: string
15+
}
16+
17+
export const Tabs = (props: Props) => {
18+
const [state, send] = useMachine(tabs.machine({ id: createUniqueId(), value: props.initValue ?? props.tabs[0].value }))
19+
20+
const api = createMemo(() => tabs.connect(state, send, normalizeProps))
21+
22+
return (
23+
<div {...api().rootProps} class="w-full text-sm font-medium text-center">
24+
<div {...api().tablistProps} class="flex flex-wrap -mb-px border-b border-base">
25+
<For each={props.tabs}>
26+
{item => (
27+
<button class={`inline-block p-4 border-b-2 border-transparent hover:text-gray-600 dark:hover:text-gray-300 transition-colors duration-300 cursor-pointer ${api().value === item.value && '!border-emerald-600 !text-emerald-600'}`} {...api().getTriggerProps({ value: item.value })}>
28+
{item.label}
29+
</button>
30+
)}
31+
</For>
32+
</div>
33+
<For each={props.tabs}>
34+
{item => (
35+
<div class="w-full p-4 text-sm mt-4 border border-base" {...api().getContentProps({ value: item.value })}>
36+
{item.content}
37+
</div>
38+
)}
39+
</For>
40+
</div>
41+
)
42+
}

src/components/ui/base/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ export * from './Select'
55
export * from './Slider'
66
export * from './Tooltip'
77
export * from './Toggle'
8+
export * from './Checkbox'
9+
export * from './Tabs'

src/stores/ui.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const showSettingsSidebar = atom(false)
66
export const showConversationEditModal = atom(false)
77
export const showEmojiPickerModal = atom(false)
88
export const showConfirmModal = atom(false)
9+
export const showShareModal = atom(false)
910

1011
export const isSendBoxFocus = atom(false)
1112
export const currentErrorMessage = atom<ErrorMessage | null>(null)

unocss.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export default defineConfig({
5959
'input-base': 'bg-transparent placeholder:op-50 dark:placeholder:op-20 focus:(ring-0 outline-none) resize-none',
6060
'button': 'mt-4 px-3 py-2 text-xs border border-base rounded-lg hv-base hover:border-base-100',
6161
'emerald-button': 'mt-4 px-3 py-2 text-xs border rounded-lg text-light-400 border-emerald-600 bg-emerald-600 hover-bg-emerald-700 hover-border-emerald-700',
62+
'emerald-light-button': 'mt-4 px-3 py-2 text-xs border rounded-lg text-emerald-400 bg-emerald/12 border-emerald-400 hover-bg-emerald-600 hover-border-emerald-600 hover-text-light-700',
6263
'max-w-base': 'max-w-3xl mx-auto',
6364
'text-error': 'text-red-700 dark:text-red-400/80',
6465
'border-error': 'border border-red-700 dark:border-red-400/80',

0 commit comments

Comments
 (0)