@interactive-inc/docs-client 0.0.1 → 0.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.
Files changed (87) hide show
  1. package/build/index.html +13 -0
  2. package/package.json +5 -2
  3. package/.tanstack/tmp/router-generator-Eq20Yx/50b11a0f488e61cf92364a7e585c1448 +0 -123
  4. package/.tanstack/tmp/router-generator-KQIYSa/aecb094e4891f9475b91de590abc8809 +0 -117
  5. package/.tanstack/tmp/router-generator-ekW2pI/aecb094e4891f9475b91de590abc8809 +0 -117
  6. package/app/components/archived-file-list-view.tsx +0 -99
  7. package/app/components/directory-file-list-view.tsx +0 -32
  8. package/app/components/directory-file-tree-node.tsx +0 -96
  9. package/app/components/directory-layout-sidebar.tsx +0 -181
  10. package/app/components/directory-page-view.tsx +0 -208
  11. package/app/components/directory-table-view.tsx +0 -383
  12. package/app/components/editable-table-cell/boolean-editable-cell.tsx +0 -44
  13. package/app/components/editable-table-cell/multi-boolean-editable-cell.tsx +0 -59
  14. package/app/components/editable-table-cell/multi-number-editable-cell.tsx +0 -62
  15. package/app/components/editable-table-cell/multi-relation-editable-cell.tsx +0 -19
  16. package/app/components/editable-table-cell/multi-select-number-editable-cell.tsx +0 -82
  17. package/app/components/editable-table-cell/multi-select-text-editable-cell.tsx +0 -82
  18. package/app/components/editable-table-cell/multi-text-editable-cell.tsx +0 -62
  19. package/app/components/editable-table-cell/number-editable-cell.tsx +0 -54
  20. package/app/components/editable-table-cell/relation-editable-cell.tsx +0 -20
  21. package/app/components/editable-table-cell/select-number-editable-cell.tsx +0 -43
  22. package/app/components/editable-table-cell/select-text-editable-cell.tsx +0 -33
  23. package/app/components/editable-table-cell/string-editable-cell.tsx +0 -42
  24. package/app/components/editable-table-cell.tsx +0 -129
  25. package/app/components/file-card.tsx +0 -120
  26. package/app/components/file-tree-icon.tsx +0 -26
  27. package/app/components/file-view/archive-restore-banner.tsx +0 -86
  28. package/app/components/file-view/csv-file-view.tsx +0 -50
  29. package/app/components/file-view/default-file-view.tsx +0 -11
  30. package/app/components/file-view/editable-csv-cell.tsx +0 -37
  31. package/app/components/file-view/editable-front-matter-view.tsx +0 -105
  32. package/app/components/file-view/file-csv-columns-view.tsx +0 -181
  33. package/app/components/file-view/file-csv-table.tsx +0 -142
  34. package/app/components/file-view/file-header.tsx +0 -115
  35. package/app/components/file-view/file-page-view.tsx +0 -165
  36. package/app/components/file-view/front-matter-input-field.tsx +0 -157
  37. package/app/components/file-view/front-matter-view.tsx +0 -30
  38. package/app/components/file-view/json-file-editor.tsx +0 -38
  39. package/app/components/file-view/markdown-file-view.tsx +0 -71
  40. package/app/components/file-view/multi-relation-select.tsx +0 -129
  41. package/app/components/file-view/render-front-matter-value.tsx +0 -57
  42. package/app/components/file-view/single-relation-select.tsx +0 -41
  43. package/app/components/file-view/sortable-csv-row.tsx +0 -57
  44. package/app/components/file-view/sortable-header.tsx +0 -30
  45. package/app/components/file-view/utils.ts +0 -8
  46. package/app/components/milestones-editor.tsx +0 -95
  47. package/app/components/page-header.tsx +0 -20
  48. package/app/components/project-view/feature-item.tsx +0 -139
  49. package/app/components/project-view/project-page-group.tsx +0 -125
  50. package/app/components/project-view/project-view.tsx +0 -230
  51. package/app/components/project-view/unlinked-features-section.tsx +0 -73
  52. package/app/components/providers.tsx +0 -21
  53. package/app/components/reload-button.tsx +0 -25
  54. package/app/components/sidebar-button.tsx +0 -13
  55. package/app/components/ui/alert.tsx +0 -66
  56. package/app/components/ui/badge.tsx +0 -46
  57. package/app/components/ui/button.tsx +0 -59
  58. package/app/components/ui/card.tsx +0 -92
  59. package/app/components/ui/dialog.tsx +0 -133
  60. package/app/components/ui/emoji-picker.tsx +0 -133
  61. package/app/components/ui/icons.tsx +0 -3
  62. package/app/components/ui/input.tsx +0 -21
  63. package/app/components/ui/select.tsx +0 -183
  64. package/app/components/ui/separator.tsx +0 -26
  65. package/app/components/ui/sheet.tsx +0 -137
  66. package/app/components/ui/sidebar.tsx +0 -724
  67. package/app/components/ui/simple-sidebar.tsx +0 -50
  68. package/app/components/ui/skeleton.tsx +0 -13
  69. package/app/components/ui/sonner.tsx +0 -23
  70. package/app/components/ui/table.tsx +0 -114
  71. package/app/components/ui/tabs.tsx +0 -53
  72. package/app/components/ui/textarea.tsx +0 -18
  73. package/app/components/ui/tooltip.tsx +0 -59
  74. package/app/components/vscode-button.tsx +0 -23
  75. package/app/hooks/use-directory-query.ts +0 -22
  76. package/app/hooks/use-file-properties-mutation.ts +0 -38
  77. package/app/hooks/use-file-query.ts +0 -21
  78. package/app/hooks/use-mobile.ts +0 -19
  79. package/app/main.css +0 -122
  80. package/app/main.tsx +0 -38
  81. package/app/routes/$.index.tsx +0 -25
  82. package/app/routes/$.tsx +0 -20
  83. package/app/routes/__root.tsx +0 -20
  84. package/app/routes/_index.tsx +0 -17
  85. package/app/routes/apps.client.$.tsx +0 -21
  86. package/components.json +0 -21
  87. package/tsconfig.index.json +0 -17
@@ -1,125 +0,0 @@
1
- import { Card } from "@/components/ui/card"
2
- import {
3
- Select,
4
- SelectContent,
5
- SelectItem,
6
- SelectTrigger,
7
- SelectValue,
8
- } from "@/components/ui/select"
9
- import type { DocFile, DocFileMd, DocRelationFile } from "@/lib/types"
10
- import { FeatureItem } from "./feature-item"
11
-
12
- function isDocFileMd(file: DocFile): file is DocFileMd {
13
- return file.type === 'markdown'
14
- }
15
-
16
- type Priority = "high" | "medium" | "low"
17
-
18
- type PageGroup = {
19
- page: DocFile
20
- features: DocFile[]
21
- }
22
-
23
- type Props = {
24
- group: PageGroup
25
- milestoneOptions?: DocRelationFile[]
26
- onMilestoneUpdate?: (featurePath: string, milestone: string) => void
27
- onPropertyUpdate?: (
28
- featurePath: string,
29
- field: string,
30
- value: unknown,
31
- ) => void
32
- allFeatures?: DocFile[]
33
- onFeatureAdd?: (pagePath: string, featurePath: string) => void
34
- onFeatureRemove?: (pagePath: string, featurePath: string) => void
35
- }
36
-
37
- export function ProjectPageGroup(props: Props) {
38
- const sortedFeatures = props.group.features
39
- .filter(isDocFileMd)
40
- .sort((a, b) => {
41
- const priorityOrder: Record<Priority, number> = {
42
- high: 0,
43
- medium: 1,
44
- low: 2,
45
- }
46
- const aPriority =
47
- ((a.content.frontMatter as Record<string, unknown>)?.priority as Priority) ||
48
- "low"
49
- const bPriority =
50
- ((b.content.frontMatter as Record<string, unknown>)?.priority as Priority) ||
51
- "low"
52
- return (priorityOrder[aPriority] || 2) - (priorityOrder[bPriority] || 2)
53
- })
54
-
55
- // このページに関連付けられていない機能を取得
56
- const linkedFeaturePaths = props.group.features.map((f) => f.path.path)
57
- const availableFeatures = (props.allFeatures || [])
58
- .filter(isDocFileMd)
59
- .filter((feature) => !linkedFeaturePaths.includes(feature.path.path))
60
-
61
- const handleFeatureAdd = (featureValue: string) => {
62
- if (featureValue && props.onFeatureAdd) {
63
- props.onFeatureAdd(props.group.page.path.path, featureValue)
64
- }
65
- }
66
-
67
- return (
68
- <Card className="w-full rounded-md p-2">
69
- <div className="flex flex-col gap-2 lg:flex-row">
70
- {/* 左側: ページ情報 */}
71
- <div className="space-y-2 lg:w-1/3">
72
- <h2 className="font-semibold text-lg">
73
- {isDocFileMd(props.group.page) ? props.group.page.content.title || props.group.page.path.name : props.group.page.path.name}
74
- </h2>
75
- <div className="text-xs opacity-50">{props.group.page.path.name}</div>
76
- {isDocFileMd(props.group.page) && props.group.page.content.description && (
77
- <p className="text-sm opacity-50">{props.group.page.content.description}</p>
78
- )}
79
- </div>
80
- {/* 右側: 関連機能一覧 */}
81
- <div className="flex-1">
82
- <div className="space-y-2">
83
- {sortedFeatures.length > 0 ? (
84
- sortedFeatures.map((feature) => (
85
- <FeatureItem
86
- key={feature.path.name}
87
- feature={feature}
88
- milestoneOptions={props.milestoneOptions}
89
- onMilestoneUpdate={props.onMilestoneUpdate}
90
- onPropertyUpdate={props.onPropertyUpdate}
91
- onFeatureRemove={(featurePath) =>
92
- props.onFeatureRemove?.(
93
- props.group.page.path.path,
94
- featurePath,
95
- )
96
- }
97
- />
98
- ))
99
- ) : (
100
- <p className="text-sm italic opacity-50">
101
- このページに関連する機能はありません
102
- </p>
103
- )}
104
-
105
- {/* 機能追加用Select */}
106
- {availableFeatures.length > 0 && (
107
- <Select value="" onValueChange={handleFeatureAdd}>
108
- <SelectTrigger className="w-full">
109
- <SelectValue placeholder="機能を追加..." />
110
- </SelectTrigger>
111
- <SelectContent>
112
- {availableFeatures.map((feature) => (
113
- <SelectItem key={feature.path.path} value={feature.path.path || ""}>
114
- {feature.content.title || feature.path.name}
115
- </SelectItem>
116
- ))}
117
- </SelectContent>
118
- </Select>
119
- )}
120
- </div>
121
- </div>
122
- </div>
123
- </Card>
124
- )
125
- }
@@ -1,230 +0,0 @@
1
- import { useSuspenseQuery } from "@tanstack/react-query"
2
- import { useState } from "react"
3
- import { Button } from "@/components/ui/button"
4
- import { useFilePropertiesMutation } from "@/hooks/use-file-properties-mutation"
5
- import { apiClient } from "@/lib/api-client"
6
- import type { DocDirectory, DocFile, DocFileMd, DocRelation, DocRelationFile } from "@/lib/types"
7
- import { ProjectPageGroup } from "./project-page-group"
8
- import { UnlinkedFeaturesSection } from "./unlinked-features-section"
9
-
10
- type Props = {
11
- project: string
12
- }
13
-
14
- type PageGroup = {
15
- page: DocFile
16
- features: DocFile[]
17
- }
18
-
19
- export function ProjectView(props: Props) {
20
- const pagesQuery = useSuspenseQuery({
21
- queryKey: ["apps/client", props.project],
22
- queryFn: async () => {
23
- const response = await apiClient.api.directories[":path{.+}"].$get({
24
- param: { path: `${props.project}/pages` },
25
- })
26
- return response.json()
27
- },
28
- })
29
-
30
- const featuresQuery = useSuspenseQuery({
31
- queryKey: ["apps/client",`products/${props.project}/features`],
32
- queryFn: async () => {
33
- const response = await apiClient.api.directories[":path{.+}"].$get({
34
- param: { path: `${props.project}/features` },
35
- })
36
- return response.json()
37
- },
38
- })
39
-
40
- const pages: DocFile[] = pagesQuery.data.files || []
41
-
42
- const features: DocFile[] = featuresQuery.data.files || []
43
-
44
- const milestoneRelation = featuresQuery.data.relations?.find(
45
- (rel: DocRelation) => {return rel.path === `${props.project}/milestones`},
46
- )
47
-
48
- const milestoneOptions = milestoneRelation?.files || []
49
-
50
- // マイルストーンフィルター状態
51
- const [selectedMilestone, setSelectedMilestone] = useState<string | null>(
52
- null,
53
- )
54
-
55
- const updatePropertiesMutation = useFilePropertiesMutation()
56
-
57
- const handleMilestoneUpdate = async (
58
- featurePath: string,
59
- milestone: string,
60
- ) => {
61
- try {
62
- await updatePropertiesMutation.mutateAsync({
63
- path: featurePath,
64
- field: "milestone",
65
- value: milestone,
66
- })
67
- await featuresQuery.refetch()
68
- } catch (error) {
69
- console.error("Failed to update milestone:", error)
70
- }
71
- }
72
-
73
- const handlePropertyUpdate = async (
74
- featurePath: string,
75
- field: string,
76
- value: unknown,
77
- ) => {
78
- try {
79
- await updatePropertiesMutation.mutateAsync({
80
- path: featurePath,
81
- field: field,
82
- value: value,
83
- })
84
- await featuresQuery.refetch()
85
- } catch (error) {
86
- console.error("Failed to update property:", error)
87
- }
88
- }
89
-
90
- const handleFeatureAdd = async (pagePath: string, featurePath: string) => {
91
- // ページのfeaturesフィールドに新しい機能を追加
92
- const page = pages.find((p: DocFile) => p.path.path === pagePath)
93
- if (!page) return
94
-
95
- const currentFeatures =
96
- (page.type === 'markdown'
97
- ? (page.content.frontMatter as Record<string, unknown>)?.features as string[]
98
- : []) || []
99
- const updatedFeatures = [...currentFeatures, featurePath]
100
-
101
- await updatePropertiesMutation.mutateAsync({
102
- path: pagePath,
103
- field: "features",
104
- value: updatedFeatures,
105
- })
106
-
107
- // 両方のクエリを再取得
108
- await Promise.all([pagesQuery.refetch(), featuresQuery.refetch()])
109
- }
110
-
111
- const handleFeatureRemove = async (pagePath: string, featurePath: string) => {
112
- try {
113
- const page = pages.find((p: DocFile) => p.path.path === pagePath)
114
- if (!page) return
115
-
116
- const currentFeatures =
117
- (page.type === 'markdown'
118
- ? (page.content.frontMatter as Record<string, unknown>)?.features as string[]
119
- : []) || []
120
-
121
- // フィーチャーを削除
122
- const updatedFeatures = currentFeatures.filter((f) => f !== featurePath)
123
-
124
- await updatePropertiesMutation.mutateAsync({
125
- path: pagePath,
126
- field: "features",
127
- value: updatedFeatures,
128
- })
129
-
130
- await Promise.all([pagesQuery.refetch(), featuresQuery.refetch()])
131
- } catch (error) {
132
- console.error("Failed to remove feature from page:", error)
133
- }
134
- }
135
-
136
- // フィルタリング関数
137
- const filterFeaturesByMilestone = (features: DocFile[]) => {
138
- if (!selectedMilestone) return features
139
- return features.filter((feature) => {
140
- if (feature.type !== 'markdown') return false
141
- const milestone = (feature.content.frontMatter as Record<string, unknown>)
142
- ?.milestone as string
143
- return milestone === selectedMilestone
144
- })
145
- }
146
-
147
- function isDocFileMdWithFeatures(file: DocFile): file is DocFileMd {
148
- return file.type === 'markdown'
149
- }
150
-
151
- // ページと関連機能をグループ化
152
- const pageGroups: PageGroup[] = pages
153
- .filter(isDocFileMdWithFeatures)
154
- .map((page: DocFileMd) => {
155
- const pageFeatures = isDocFileMdWithFeatures(page)
156
- ? ((page.content.frontMatter as Record<string, unknown>)?.features as string[]) || []
157
- : []
158
- const relatedFeatures = features.filter((feature: DocFile) => {
159
- return pageFeatures.includes(feature.path.path)
160
- })
161
-
162
- // フィルタリング適用
163
- const filteredFeatures = filterFeaturesByMilestone(relatedFeatures).filter((feature): feature is DocFileMd => feature.type === 'markdown')
164
-
165
- return {
166
- page,
167
- features: filteredFeatures,
168
- }
169
- })
170
-
171
- // 関連付けられていない機能
172
- const allLinkedFeatures = pageGroups.flatMap((group) =>
173
- group.features.map((f) => f.path.path),
174
- )
175
-
176
- const unlinkedFeatures = filterFeaturesByMilestone(
177
- features.filter(
178
- (feature: DocFile) => !allLinkedFeatures.includes(feature.path.path),
179
- ),
180
- )
181
-
182
- return (
183
- <main className="w-full space-y-2 p-2">
184
- {/* マイルストーンフィルターボタン */}
185
- <div className="flex flex-wrap gap-2">
186
- <Button
187
- variant={selectedMilestone === null ? "default" : "secondary"}
188
- onClick={() => setSelectedMilestone(null)}
189
- size="sm"
190
- >
191
- すべて
192
- </Button>
193
- {milestoneOptions.map((milestone: DocRelationFile) => (
194
- <Button
195
- key={milestone.name}
196
- variant={
197
- selectedMilestone === milestone.name ? "default" : "secondary"
198
- }
199
- onClick={() => setSelectedMilestone(milestone.name)}
200
- size="sm"
201
- >
202
- {milestone.name}
203
- </Button>
204
- ))}
205
- </div>
206
-
207
- {/* ページグループ */}
208
- <div className="space-y-2">
209
- {pageGroups.map((group) => (
210
- <ProjectPageGroup
211
- key={group.page.path.name}
212
- group={group}
213
- milestoneOptions={milestoneOptions}
214
- onMilestoneUpdate={handleMilestoneUpdate}
215
- onPropertyUpdate={handlePropertyUpdate}
216
- allFeatures={features}
217
- onFeatureAdd={handleFeatureAdd}
218
- onFeatureRemove={handleFeatureRemove}
219
- />
220
- ))}
221
- <UnlinkedFeaturesSection
222
- unlinkedFeatures={unlinkedFeatures.filter((feature): feature is DocFileMd => 'frontMatter' in feature && 'title' in feature)}
223
- milestoneOptions={milestoneOptions}
224
- onMilestoneUpdate={handleMilestoneUpdate}
225
- onPropertyUpdate={handlePropertyUpdate}
226
- />
227
- </div>
228
- </main>
229
- )
230
- }
@@ -1,73 +0,0 @@
1
- import { Badge } from "@/components/ui/badge"
2
- import { Card } from "@/components/ui/card"
3
- import type { DocFile, DocFileMd, DocRelationFile } from "@/lib/types"
4
- import { FeatureItem } from "./feature-item"
5
-
6
- function isDocFileMd(file: DocFile): file is DocFileMd {
7
- return file.type === 'markdown'
8
- }
9
-
10
- type Priority = "high" | "medium" | "low"
11
-
12
- type Props = {
13
- unlinkedFeatures: DocFile[]
14
- milestoneOptions?: DocRelationFile[]
15
- onMilestoneUpdate?: (featurePath: string, milestone: string) => void
16
- onPropertyUpdate?: (
17
- featurePath: string,
18
- field: string,
19
- value: unknown,
20
- ) => void
21
- }
22
-
23
- export function UnlinkedFeaturesSection(props: Props) {
24
- if (props.unlinkedFeatures.length === 0) {
25
- return null
26
- }
27
-
28
- const sortedFeatures = props.unlinkedFeatures
29
- .filter(isDocFileMd)
30
- .sort((a, b) => {
31
- const priorityOrder: Record<Priority, number> = {
32
- high: 0,
33
- medium: 1,
34
- low: 2,
35
- }
36
- const aPriority =
37
- ((a.content.frontMatter as Record<string, unknown>)?.priority as Priority) ||
38
- "low"
39
- const bPriority =
40
- ((b.content.frontMatter as Record<string, unknown>)?.priority as Priority) ||
41
- "low"
42
- return (priorityOrder[aPriority] || 2) - (priorityOrder[bPriority] || 2)
43
- })
44
-
45
- return (
46
- <Card className="w-full p-2">
47
- <div className="flex gap-2">
48
- <div className="w-1/3 border-r pr-4">
49
- <h2 className="font-semibold text-lg">未関連付け機能</h2>
50
- <p className="text-gray-600 text-sm">
51
- ページに関連付けられていない機能
52
- </p>
53
- <Badge variant="outline" className="mt-2">
54
- {props.unlinkedFeatures.length}機能
55
- </Badge>
56
- </div>
57
- <div className="flex-1">
58
- <div className="space-y-3">
59
- {sortedFeatures.map((feature) => (
60
- <FeatureItem
61
- key={feature.path.name}
62
- feature={feature}
63
- milestoneOptions={props.milestoneOptions}
64
- onMilestoneUpdate={props.onMilestoneUpdate}
65
- onPropertyUpdate={props.onPropertyUpdate}
66
- />
67
- ))}
68
- </div>
69
- </div>
70
- </div>
71
- </Card>
72
- )
73
- }
@@ -1,21 +0,0 @@
1
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
2
- import { useState } from "react"
3
-
4
- export function Providers(props: { children: React.ReactNode }) {
5
- const [queryClient] = useState(() => {
6
- return new QueryClient({
7
- defaultOptions: {
8
- queries: {
9
- staleTime: 60 * 1000, // 1分
10
- retry: 1,
11
- },
12
- },
13
- })
14
- })
15
-
16
- return (
17
- <QueryClientProvider client={queryClient}>
18
- {props.children}
19
- </QueryClientProvider>
20
- )
21
- }
@@ -1,25 +0,0 @@
1
- import { RefreshCw } from "lucide-react"
2
- import { Button } from "./ui/button"
3
-
4
- type Props = {
5
- onReload: () => void
6
- size?: "sm" | "default" | "lg" | "icon"
7
- variant?: "default" | "secondary" | "ghost" | "outline"
8
- disabled?: boolean
9
- }
10
-
11
- /**
12
- * リロードボタンコンポーネント
13
- */
14
- export function ReloadButton(props: Props) {
15
- return (
16
- <Button
17
- size={props.size || "sm"}
18
- variant={props.variant || "secondary"}
19
- onClick={props.onReload}
20
- disabled={props.disabled}
21
- >
22
- <RefreshCw />
23
- </Button>
24
- )
25
- }
@@ -1,13 +0,0 @@
1
- import { PanelLeftIcon } from "lucide-react"
2
- import { Button } from "@/components/ui/button"
3
- import { useSidebar } from "@/components/ui/sidebar"
4
-
5
- export function SidebarButton() {
6
- const sidebar = useSidebar()
7
-
8
- return (
9
- <Button variant={"outline"} onClick={sidebar.toggleSidebar} size={"icon"}>
10
- <PanelLeftIcon />
11
- </Button>
12
- )
13
- }
@@ -1,66 +0,0 @@
1
- import { cva, type VariantProps } from "class-variance-authority"
2
- import type * as React from "react"
3
-
4
- import { cn } from "@/lib/utils"
5
-
6
- const alertVariants = cva(
7
- "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
8
- {
9
- variants: {
10
- variant: {
11
- default: "bg-card text-card-foreground",
12
- destructive:
13
- "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
14
- },
15
- },
16
- defaultVariants: {
17
- variant: "default",
18
- },
19
- },
20
- )
21
-
22
- function Alert({
23
- className,
24
- variant,
25
- ...props
26
- }: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
27
- return (
28
- <div
29
- data-slot="alert"
30
- role="alert"
31
- className={cn(alertVariants({ variant }), className)}
32
- {...props}
33
- />
34
- )
35
- }
36
-
37
- function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
38
- return (
39
- <div
40
- data-slot="alert-title"
41
- className={cn(
42
- "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
43
- className,
44
- )}
45
- {...props}
46
- />
47
- )
48
- }
49
-
50
- function AlertDescription({
51
- className,
52
- ...props
53
- }: React.ComponentProps<"div">) {
54
- return (
55
- <div
56
- data-slot="alert-description"
57
- className={cn(
58
- "col-start-2 grid justify-items-start gap-1 text-muted-foreground text-sm [&_p]:leading-relaxed",
59
- className,
60
- )}
61
- {...props}
62
- />
63
- )
64
- }
65
-
66
- export { Alert, AlertTitle, AlertDescription }
@@ -1,46 +0,0 @@
1
- import { cva, type VariantProps } from "class-variance-authority"
2
- import { Slot as SlotPrimitive } from "radix-ui"
3
- import type * as React from "react"
4
-
5
- import { cn } from "@/lib/utils"
6
-
7
- const badgeVariants = cva(
8
- "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
9
- {
10
- variants: {
11
- variant: {
12
- default:
13
- "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
14
- secondary:
15
- "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
16
- destructive:
17
- "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
18
- outline:
19
- "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
20
- },
21
- },
22
- defaultVariants: {
23
- variant: "default",
24
- },
25
- },
26
- )
27
-
28
- function Badge({
29
- className,
30
- variant,
31
- asChild = false,
32
- ...props
33
- }: React.ComponentProps<"span"> &
34
- VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
35
- const Comp = asChild ? SlotPrimitive.Slot : "span"
36
-
37
- return (
38
- <Comp
39
- data-slot="badge"
40
- className={cn(badgeVariants({ variant }), className)}
41
- {...props}
42
- />
43
- )
44
- }
45
-
46
- export { Badge, badgeVariants }
@@ -1,59 +0,0 @@
1
- import { cva, type VariantProps } from "class-variance-authority"
2
- import { Slot as SlotPrimitive } from "radix-ui"
3
- import type * as React from "react"
4
-
5
- import { cn } from "@/lib/utils"
6
-
7
- const buttonVariants = cva(
8
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
9
- {
10
- variants: {
11
- variant: {
12
- default:
13
- "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
14
- destructive:
15
- "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
16
- outline:
17
- "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
18
- secondary:
19
- "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
20
- ghost:
21
- "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
22
- link: "text-primary underline-offset-4 hover:underline",
23
- },
24
- size: {
25
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
26
- sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
27
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
28
- icon: "size-9",
29
- },
30
- },
31
- defaultVariants: {
32
- variant: "default",
33
- size: "default",
34
- },
35
- },
36
- )
37
-
38
- function Button({
39
- className,
40
- variant,
41
- size,
42
- asChild = false,
43
- ...props
44
- }: React.ComponentProps<"button"> &
45
- VariantProps<typeof buttonVariants> & {
46
- asChild?: boolean
47
- }) {
48
- const Comp = asChild ? SlotPrimitive.Slot : "button"
49
-
50
- return (
51
- <Comp
52
- data-slot="button"
53
- className={cn(buttonVariants({ variant, size, className }))}
54
- {...props}
55
- />
56
- )
57
- }
58
-
59
- export { Button, buttonVariants }