@interactive-inc/docs-client 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/docs.js +3 -0
- package/build/assets/index.css +1 -1
- package/build/assets/index.js +53 -53
- package/build/index.html +13 -0
- package/build/index.js +24057 -16
- package/package.json +13 -6
- package/.tanstack/tmp/router-generator-Eq20Yx/50b11a0f488e61cf92364a7e585c1448 +0 -123
- package/.tanstack/tmp/router-generator-KQIYSa/aecb094e4891f9475b91de590abc8809 +0 -117
- package/.tanstack/tmp/router-generator-ekW2pI/aecb094e4891f9475b91de590abc8809 +0 -117
- package/app/components/archived-file-list-view.tsx +0 -99
- package/app/components/directory-file-list-view.tsx +0 -32
- package/app/components/directory-file-tree-node.tsx +0 -96
- package/app/components/directory-layout-sidebar.tsx +0 -181
- package/app/components/directory-page-view.tsx +0 -208
- package/app/components/directory-table-view.tsx +0 -383
- package/app/components/editable-table-cell/boolean-editable-cell.tsx +0 -44
- package/app/components/editable-table-cell/multi-boolean-editable-cell.tsx +0 -59
- package/app/components/editable-table-cell/multi-number-editable-cell.tsx +0 -62
- package/app/components/editable-table-cell/multi-relation-editable-cell.tsx +0 -19
- package/app/components/editable-table-cell/multi-select-number-editable-cell.tsx +0 -82
- package/app/components/editable-table-cell/multi-select-text-editable-cell.tsx +0 -82
- package/app/components/editable-table-cell/multi-text-editable-cell.tsx +0 -62
- package/app/components/editable-table-cell/number-editable-cell.tsx +0 -54
- package/app/components/editable-table-cell/relation-editable-cell.tsx +0 -20
- package/app/components/editable-table-cell/select-number-editable-cell.tsx +0 -43
- package/app/components/editable-table-cell/select-text-editable-cell.tsx +0 -33
- package/app/components/editable-table-cell/string-editable-cell.tsx +0 -42
- package/app/components/editable-table-cell.tsx +0 -129
- package/app/components/file-card.tsx +0 -120
- package/app/components/file-tree-icon.tsx +0 -26
- package/app/components/file-view/archive-restore-banner.tsx +0 -86
- package/app/components/file-view/csv-file-view.tsx +0 -50
- package/app/components/file-view/default-file-view.tsx +0 -11
- package/app/components/file-view/editable-csv-cell.tsx +0 -37
- package/app/components/file-view/editable-front-matter-view.tsx +0 -105
- package/app/components/file-view/file-csv-columns-view.tsx +0 -181
- package/app/components/file-view/file-csv-table.tsx +0 -142
- package/app/components/file-view/file-header.tsx +0 -115
- package/app/components/file-view/file-page-view.tsx +0 -165
- package/app/components/file-view/front-matter-input-field.tsx +0 -157
- package/app/components/file-view/front-matter-view.tsx +0 -30
- package/app/components/file-view/json-file-editor.tsx +0 -38
- package/app/components/file-view/markdown-file-view.tsx +0 -71
- package/app/components/file-view/multi-relation-select.tsx +0 -129
- package/app/components/file-view/render-front-matter-value.tsx +0 -57
- package/app/components/file-view/single-relation-select.tsx +0 -41
- package/app/components/file-view/sortable-csv-row.tsx +0 -57
- package/app/components/file-view/sortable-header.tsx +0 -30
- package/app/components/file-view/utils.ts +0 -8
- package/app/components/milestones-editor.tsx +0 -95
- package/app/components/page-header.tsx +0 -20
- package/app/components/project-view/feature-item.tsx +0 -139
- package/app/components/project-view/project-page-group.tsx +0 -125
- package/app/components/project-view/project-view.tsx +0 -230
- package/app/components/project-view/unlinked-features-section.tsx +0 -73
- package/app/components/providers.tsx +0 -21
- package/app/components/reload-button.tsx +0 -25
- package/app/components/sidebar-button.tsx +0 -13
- package/app/components/ui/alert.tsx +0 -66
- package/app/components/ui/badge.tsx +0 -46
- package/app/components/ui/button.tsx +0 -59
- package/app/components/ui/card.tsx +0 -92
- package/app/components/ui/dialog.tsx +0 -133
- package/app/components/ui/emoji-picker.tsx +0 -133
- package/app/components/ui/icons.tsx +0 -3
- package/app/components/ui/input.tsx +0 -21
- package/app/components/ui/select.tsx +0 -183
- package/app/components/ui/separator.tsx +0 -26
- package/app/components/ui/sheet.tsx +0 -137
- package/app/components/ui/sidebar.tsx +0 -724
- package/app/components/ui/simple-sidebar.tsx +0 -50
- package/app/components/ui/skeleton.tsx +0 -13
- package/app/components/ui/sonner.tsx +0 -23
- package/app/components/ui/table.tsx +0 -114
- package/app/components/ui/tabs.tsx +0 -53
- package/app/components/ui/textarea.tsx +0 -18
- package/app/components/ui/tooltip.tsx +0 -59
- package/app/components/vscode-button.tsx +0 -23
- package/app/hooks/use-directory-query.ts +0 -22
- package/app/hooks/use-file-properties-mutation.ts +0 -38
- package/app/hooks/use-file-query.ts +0 -21
- package/app/hooks/use-mobile.ts +0 -19
- package/app/main.css +0 -122
- package/app/main.tsx +0 -38
- package/app/routes/$.index.tsx +0 -25
- package/app/routes/$.tsx +0 -20
- package/app/routes/__root.tsx +0 -20
- package/app/routes/_index.tsx +0 -17
- package/app/routes/apps.client.$.tsx +0 -21
- package/build/index.d.ts +0 -2
- package/build/index.d.ts.map +0 -1
- package/components.json +0 -21
- package/tsconfig.index.json +0 -17
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { X } from "lucide-react"
|
|
2
|
-
import { useState } from "react"
|
|
3
|
-
import { Badge } from "@/components/ui/badge"
|
|
4
|
-
import { Button } from "@/components/ui/button"
|
|
5
|
-
|
|
6
|
-
type Props = {
|
|
7
|
-
value: string[]
|
|
8
|
-
options: string[]
|
|
9
|
-
onUpdate: (value: string[]) => void
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* 複数選択テキストセル
|
|
14
|
-
*/
|
|
15
|
-
export function MultiSelectTextEditableCell(props: Props) {
|
|
16
|
-
const [isOpen, setIsOpen] = useState(false)
|
|
17
|
-
const currentValues = props.value || []
|
|
18
|
-
|
|
19
|
-
const handleToggle = (option: string) => {
|
|
20
|
-
const isSelected = currentValues.includes(option)
|
|
21
|
-
const newValues = isSelected
|
|
22
|
-
? currentValues.filter((v) => v !== option)
|
|
23
|
-
: [...currentValues, option]
|
|
24
|
-
props.onUpdate(newValues)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const handleRemove = (value: string) => {
|
|
28
|
-
const newValues = currentValues.filter((v) => v !== value)
|
|
29
|
-
props.onUpdate(newValues)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return (
|
|
33
|
-
<div className="relative">
|
|
34
|
-
<div className="flex min-h-8 flex-wrap gap-1 rounded-md border p-2">
|
|
35
|
-
{currentValues.map((value) => (
|
|
36
|
-
<Badge
|
|
37
|
-
key={value}
|
|
38
|
-
variant="secondary"
|
|
39
|
-
className="flex items-center gap-1"
|
|
40
|
-
>
|
|
41
|
-
{value}
|
|
42
|
-
<Button
|
|
43
|
-
size="sm"
|
|
44
|
-
variant="ghost"
|
|
45
|
-
className="h-4 w-4 p-0"
|
|
46
|
-
onClick={() => handleRemove(value)}
|
|
47
|
-
>
|
|
48
|
-
<X className="h-3 w-3" />
|
|
49
|
-
</Button>
|
|
50
|
-
</Badge>
|
|
51
|
-
))}
|
|
52
|
-
<Button
|
|
53
|
-
variant="ghost"
|
|
54
|
-
size="sm"
|
|
55
|
-
onClick={() => setIsOpen(!isOpen)}
|
|
56
|
-
className="text-muted-foreground"
|
|
57
|
-
>
|
|
58
|
-
追加
|
|
59
|
-
</Button>
|
|
60
|
-
</div>
|
|
61
|
-
{isOpen && (
|
|
62
|
-
<div className="absolute z-10 mt-1 w-full rounded-md border bg-white shadow-lg">
|
|
63
|
-
{props.options
|
|
64
|
-
.filter((option) => !currentValues.includes(option))
|
|
65
|
-
.map((option) => (
|
|
66
|
-
<button
|
|
67
|
-
type="button"
|
|
68
|
-
key={option}
|
|
69
|
-
className="w-full px-3 py-2 text-left hover:bg-gray-100"
|
|
70
|
-
onClick={() => {
|
|
71
|
-
handleToggle(option)
|
|
72
|
-
setIsOpen(false)
|
|
73
|
-
}}
|
|
74
|
-
>
|
|
75
|
-
{option}
|
|
76
|
-
</button>
|
|
77
|
-
))}
|
|
78
|
-
</div>
|
|
79
|
-
)}
|
|
80
|
-
</div>
|
|
81
|
-
)
|
|
82
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react"
|
|
2
|
-
import { Input } from "@/components/ui/input"
|
|
3
|
-
|
|
4
|
-
type Props = {
|
|
5
|
-
value: unknown
|
|
6
|
-
onUpdate: (value: unknown) => void
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function MultiTextEditableCell(props: Props) {
|
|
10
|
-
const formatValue = (value: unknown): string => {
|
|
11
|
-
if (value === undefined || value === null) {
|
|
12
|
-
return ""
|
|
13
|
-
}
|
|
14
|
-
return Array.isArray(value) ? value.join(", ") : ""
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const [editValue, setEditValue] = useState(formatValue(props.value))
|
|
18
|
-
|
|
19
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
setEditValue(formatValue(props.value))
|
|
22
|
-
}, [props.value])
|
|
23
|
-
|
|
24
|
-
const parseValue = (text: string): unknown => {
|
|
25
|
-
if (text === "") {
|
|
26
|
-
return undefined
|
|
27
|
-
}
|
|
28
|
-
return text
|
|
29
|
-
.split(",")
|
|
30
|
-
.map((s) => s.trim())
|
|
31
|
-
.filter(Boolean)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const displayValue = formatValue(props.value)
|
|
35
|
-
|
|
36
|
-
const handleBlur = () => {
|
|
37
|
-
const parsedValue = parseValue(editValue)
|
|
38
|
-
if (parsedValue !== props.value) {
|
|
39
|
-
props.onUpdate(parsedValue)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
44
|
-
if (e.key === "Enter") {
|
|
45
|
-
handleBlur()
|
|
46
|
-
}
|
|
47
|
-
if (e.key === "Escape") {
|
|
48
|
-
setEditValue(displayValue)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return (
|
|
53
|
-
<Input
|
|
54
|
-
type="text"
|
|
55
|
-
value={editValue}
|
|
56
|
-
onChange={(e) => setEditValue(e.target.value)}
|
|
57
|
-
onBlur={handleBlur}
|
|
58
|
-
onKeyDown={handleKeyDown}
|
|
59
|
-
placeholder={displayValue || "-"}
|
|
60
|
-
/>
|
|
61
|
-
)
|
|
62
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react"
|
|
2
|
-
import { Input } from "@/components/ui/input"
|
|
3
|
-
|
|
4
|
-
type Props = {
|
|
5
|
-
value: number | null
|
|
6
|
-
onUpdate: (value: number | null) => void
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function NumberEditableCell(props: Props) {
|
|
10
|
-
const [_isEditing, setIsEditing] = useState(false)
|
|
11
|
-
|
|
12
|
-
const displayValue =
|
|
13
|
-
props.value !== undefined && props.value !== null ? String(props.value) : ""
|
|
14
|
-
const [editValue, setEditValue] = useState(displayValue)
|
|
15
|
-
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
setEditValue(displayValue)
|
|
18
|
-
}, [displayValue])
|
|
19
|
-
|
|
20
|
-
const _handleClick = () => {
|
|
21
|
-
setIsEditing(true)
|
|
22
|
-
setEditValue(props.value ? String(props.value) : "")
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const handleBlur = () => {
|
|
26
|
-
setIsEditing(false)
|
|
27
|
-
const num = Number(editValue)
|
|
28
|
-
const parsedValue =
|
|
29
|
-
editValue === "" ? undefined : Number.isNaN(num) ? undefined : num
|
|
30
|
-
if (parsedValue !== props.value) {
|
|
31
|
-
props.onUpdate(parsedValue ?? null)
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
36
|
-
if (e.key === "Enter") {
|
|
37
|
-
handleBlur()
|
|
38
|
-
}
|
|
39
|
-
if (e.key === "Escape") {
|
|
40
|
-
setIsEditing(false)
|
|
41
|
-
setEditValue(props.value ? String(props.value) : "")
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<Input
|
|
47
|
-
type="number"
|
|
48
|
-
value={editValue}
|
|
49
|
-
onChange={(e) => setEditValue(e.target.value)}
|
|
50
|
-
onBlur={handleBlur}
|
|
51
|
-
onKeyDown={handleKeyDown}
|
|
52
|
-
/>
|
|
53
|
-
)
|
|
54
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { SingleRelationSelect } from "@/components/file-view/single-relation-select"
|
|
2
|
-
import type { DocRelationFile } from "@/lib/types"
|
|
3
|
-
|
|
4
|
-
type Props = {
|
|
5
|
-
value: unknown
|
|
6
|
-
onUpdate: (value: unknown) => void
|
|
7
|
-
relationOptions?: DocRelationFile[]
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function RelationEditableCell(props: Props) {
|
|
11
|
-
return (
|
|
12
|
-
<SingleRelationSelect
|
|
13
|
-
value={(props.value as string) || ""}
|
|
14
|
-
relationOptions={props.relationOptions}
|
|
15
|
-
onValueChange={(value) => {
|
|
16
|
-
props.onUpdate(value)
|
|
17
|
-
}}
|
|
18
|
-
/>
|
|
19
|
-
)
|
|
20
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Select,
|
|
3
|
-
SelectContent,
|
|
4
|
-
SelectItem,
|
|
5
|
-
SelectTrigger,
|
|
6
|
-
SelectValue,
|
|
7
|
-
} from "@/components/ui/select"
|
|
8
|
-
|
|
9
|
-
type Props = {
|
|
10
|
-
value: number
|
|
11
|
-
options: number[]
|
|
12
|
-
onValueChange: (value: number) => void
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* 数値選択セル
|
|
17
|
-
*/
|
|
18
|
-
export function SelectNumberEditableCell(props: Props) {
|
|
19
|
-
const handleValueChange = (value: string) => {
|
|
20
|
-
const numValue = Number.parseInt(value, 10)
|
|
21
|
-
if (!Number.isNaN(numValue)) {
|
|
22
|
-
props.onValueChange(numValue)
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<Select
|
|
28
|
-
value={props.value?.toString() || ""}
|
|
29
|
-
onValueChange={handleValueChange}
|
|
30
|
-
>
|
|
31
|
-
<SelectTrigger className="w-full bg-background">
|
|
32
|
-
<SelectValue placeholder="選択してください" />
|
|
33
|
-
</SelectTrigger>
|
|
34
|
-
<SelectContent>
|
|
35
|
-
{props.options.map((option) => (
|
|
36
|
-
<SelectItem key={option} value={option.toString()}>
|
|
37
|
-
{option}
|
|
38
|
-
</SelectItem>
|
|
39
|
-
))}
|
|
40
|
-
</SelectContent>
|
|
41
|
-
</Select>
|
|
42
|
-
)
|
|
43
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Select,
|
|
3
|
-
SelectContent,
|
|
4
|
-
SelectItem,
|
|
5
|
-
SelectTrigger,
|
|
6
|
-
SelectValue,
|
|
7
|
-
} from "@/components/ui/select"
|
|
8
|
-
|
|
9
|
-
type Props = {
|
|
10
|
-
value: string
|
|
11
|
-
options: string[]
|
|
12
|
-
onValueChange: (value: string) => void
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* テキスト選択セル
|
|
17
|
-
*/
|
|
18
|
-
export function SelectTextEditableCell(props: Props) {
|
|
19
|
-
return (
|
|
20
|
-
<Select value={props.value || ""} onValueChange={props.onValueChange}>
|
|
21
|
-
<SelectTrigger className="w-full bg-background">
|
|
22
|
-
<SelectValue placeholder="選択してください" />
|
|
23
|
-
</SelectTrigger>
|
|
24
|
-
<SelectContent>
|
|
25
|
-
{props.options.map((option) => (
|
|
26
|
-
<SelectItem key={option} value={option}>
|
|
27
|
-
{option}
|
|
28
|
-
</SelectItem>
|
|
29
|
-
))}
|
|
30
|
-
</SelectContent>
|
|
31
|
-
</Select>
|
|
32
|
-
)
|
|
33
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react"
|
|
2
|
-
import { Input } from "@/components/ui/input"
|
|
3
|
-
|
|
4
|
-
type Props = {
|
|
5
|
-
value: unknown
|
|
6
|
-
onUpdate: (value: unknown) => void
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function StringEditableCell(props: Props) {
|
|
10
|
-
const displayValue = props.value ? String(props.value) : ""
|
|
11
|
-
const [editValue, setEditValue] = useState(displayValue)
|
|
12
|
-
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
setEditValue(displayValue)
|
|
15
|
-
}, [displayValue])
|
|
16
|
-
|
|
17
|
-
const handleBlur = () => {
|
|
18
|
-
if (editValue !== props.value) {
|
|
19
|
-
props.onUpdate(editValue || undefined)
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
24
|
-
if (e.key === "Enter") {
|
|
25
|
-
handleBlur()
|
|
26
|
-
}
|
|
27
|
-
if (e.key === "Escape") {
|
|
28
|
-
setEditValue(displayValue)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return (
|
|
33
|
-
<Input
|
|
34
|
-
type="text"
|
|
35
|
-
value={editValue}
|
|
36
|
-
onChange={(e) => setEditValue(e.target.value)}
|
|
37
|
-
onBlur={handleBlur}
|
|
38
|
-
onKeyDown={handleKeyDown}
|
|
39
|
-
placeholder={displayValue || "-"}
|
|
40
|
-
/>
|
|
41
|
-
)
|
|
42
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import type { DocRelationFile } from "@/lib/types"
|
|
2
|
-
import { BooleanEditableCell } from "./editable-table-cell/boolean-editable-cell"
|
|
3
|
-
import { MultiBooleanEditableCell } from "./editable-table-cell/multi-boolean-editable-cell"
|
|
4
|
-
import { MultiNumberEditableCell } from "./editable-table-cell/multi-number-editable-cell"
|
|
5
|
-
import { MultiRelationEditableCell } from "./editable-table-cell/multi-relation-editable-cell"
|
|
6
|
-
import { MultiSelectNumberEditableCell } from "./editable-table-cell/multi-select-number-editable-cell"
|
|
7
|
-
import { MultiSelectTextEditableCell } from "./editable-table-cell/multi-select-text-editable-cell"
|
|
8
|
-
import { MultiTextEditableCell } from "./editable-table-cell/multi-text-editable-cell"
|
|
9
|
-
import { NumberEditableCell } from "./editable-table-cell/number-editable-cell"
|
|
10
|
-
import { RelationEditableCell } from "./editable-table-cell/relation-editable-cell"
|
|
11
|
-
import { SelectNumberEditableCell } from "./editable-table-cell/select-number-editable-cell"
|
|
12
|
-
import { SelectTextEditableCell } from "./editable-table-cell/select-text-editable-cell"
|
|
13
|
-
import { StringEditableCell } from "./editable-table-cell/string-editable-cell"
|
|
14
|
-
|
|
15
|
-
type Props = {
|
|
16
|
-
value: unknown
|
|
17
|
-
type: string
|
|
18
|
-
onUpdate: (value: unknown) => void
|
|
19
|
-
path?: string | null
|
|
20
|
-
relationOptions?: DocRelationFile[]
|
|
21
|
-
selectOptions?: string[] | number[]
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function EditableTableCell(props: Props) {
|
|
25
|
-
// Boolean型の場合
|
|
26
|
-
if (props.type === "boolean") {
|
|
27
|
-
return <BooleanEditableCell value={props.value} onUpdate={props.onUpdate} />
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// 数値型の場合
|
|
31
|
-
if (props.type === "number") {
|
|
32
|
-
return (
|
|
33
|
-
<NumberEditableCell
|
|
34
|
-
value={props.value as number}
|
|
35
|
-
onUpdate={props.onUpdate}
|
|
36
|
-
/>
|
|
37
|
-
)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// 単一リレーション型の場合
|
|
41
|
-
if (props.type === "relation") {
|
|
42
|
-
return (
|
|
43
|
-
<RelationEditableCell
|
|
44
|
-
value={props.value}
|
|
45
|
-
onUpdate={props.onUpdate}
|
|
46
|
-
relationOptions={props.relationOptions}
|
|
47
|
-
/>
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// 複数リレーション型の場合
|
|
52
|
-
if (props.type === "multi-relation") {
|
|
53
|
-
return (
|
|
54
|
-
<MultiRelationEditableCell
|
|
55
|
-
value={props.value}
|
|
56
|
-
onUpdate={props.onUpdate}
|
|
57
|
-
relationOptions={props.relationOptions}
|
|
58
|
-
/>
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// 複数テキスト型の場合
|
|
63
|
-
if (props.type === "multi-text") {
|
|
64
|
-
return (
|
|
65
|
-
<MultiTextEditableCell value={props.value} onUpdate={props.onUpdate} />
|
|
66
|
-
)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// 複数数値型の場合
|
|
70
|
-
if (props.type === "multi-number") {
|
|
71
|
-
return (
|
|
72
|
-
<MultiNumberEditableCell value={props.value} onUpdate={props.onUpdate} />
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// 複数Boolean型の場合
|
|
77
|
-
if (props.type === "multi-boolean") {
|
|
78
|
-
return (
|
|
79
|
-
<MultiBooleanEditableCell value={props.value} onUpdate={props.onUpdate} />
|
|
80
|
-
)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// 選択テキスト型の場合
|
|
84
|
-
if (props.type === "select-text" && props.selectOptions) {
|
|
85
|
-
return (
|
|
86
|
-
<SelectTextEditableCell
|
|
87
|
-
value={props.value as string}
|
|
88
|
-
options={props.selectOptions as string[]}
|
|
89
|
-
onValueChange={props.onUpdate}
|
|
90
|
-
/>
|
|
91
|
-
)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// 選択数値型の場合
|
|
95
|
-
if (props.type === "select-number" && props.selectOptions) {
|
|
96
|
-
return (
|
|
97
|
-
<SelectNumberEditableCell
|
|
98
|
-
value={props.value as number}
|
|
99
|
-
options={props.selectOptions as number[]}
|
|
100
|
-
onValueChange={props.onUpdate}
|
|
101
|
-
/>
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// 複数選択テキスト型の場合
|
|
106
|
-
if (props.type === "multi-select-text" && props.selectOptions) {
|
|
107
|
-
return (
|
|
108
|
-
<MultiSelectTextEditableCell
|
|
109
|
-
value={props.value as string[]}
|
|
110
|
-
options={props.selectOptions as string[]}
|
|
111
|
-
onUpdate={props.onUpdate}
|
|
112
|
-
/>
|
|
113
|
-
)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// 複数選択数値型の場合
|
|
117
|
-
if (props.type === "multi-select-number" && props.selectOptions) {
|
|
118
|
-
return (
|
|
119
|
-
<MultiSelectNumberEditableCell
|
|
120
|
-
value={props.value as number[]}
|
|
121
|
-
options={props.selectOptions as number[]}
|
|
122
|
-
onUpdate={props.onUpdate}
|
|
123
|
-
/>
|
|
124
|
-
)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// その他(文字列型)の場合
|
|
128
|
-
return <StringEditableCell value={props.value} onUpdate={props.onUpdate} />
|
|
129
|
-
}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { useMutation } from "@tanstack/react-query"
|
|
2
|
-
import { Link } from "@tanstack/react-router"
|
|
3
|
-
import { Archive, Trash2 } from "lucide-react"
|
|
4
|
-
import { useState } from "react"
|
|
5
|
-
import { Button } from "@/components/ui/button"
|
|
6
|
-
import { apiClient } from "@/lib/api-client"
|
|
7
|
-
import { normalizePath } from "@/lib/path-utils"
|
|
8
|
-
import type { DocFileUnknown } from "@/lib/types"
|
|
9
|
-
|
|
10
|
-
type Props = {
|
|
11
|
-
file: DocFileUnknown
|
|
12
|
-
onDataChanged?: () => void
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function FileCard(props: Props) {
|
|
16
|
-
const [deleteConfirmFiles, setDeleteConfirmFiles] = useState<Set<string>>(
|
|
17
|
-
new Set(),
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
const deleteFileMutation = useMutation({
|
|
21
|
-
async mutationFn(filePath: string) {
|
|
22
|
-
const path = normalizePath(filePath)
|
|
23
|
-
const pathSegments = path
|
|
24
|
-
.split("/")
|
|
25
|
-
.map((segment) => encodeURIComponent(segment))
|
|
26
|
-
const encodedPath = pathSegments.join("/")
|
|
27
|
-
const resp = await fetch(`/api/files/${encodedPath}`, {
|
|
28
|
-
method: "DELETE",
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
if (!resp.ok) {
|
|
32
|
-
const errorText = await resp.text()
|
|
33
|
-
throw new Error(`Failed to delete file: ${errorText}`)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return resp.json()
|
|
37
|
-
},
|
|
38
|
-
onSuccess() {
|
|
39
|
-
if (!props.onDataChanged) return
|
|
40
|
-
props.onDataChanged()
|
|
41
|
-
},
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
const archiveFileMutation = useMutation({
|
|
45
|
-
async mutationFn(filePath: string) {
|
|
46
|
-
const endpoint = apiClient.api.files[":path{.+}"]
|
|
47
|
-
const resp = await endpoint.$put({
|
|
48
|
-
param: { path: normalizePath(filePath) },
|
|
49
|
-
json: {
|
|
50
|
-
properties: null,
|
|
51
|
-
content: null,
|
|
52
|
-
title: null,
|
|
53
|
-
description: null,
|
|
54
|
-
isArchived: true,
|
|
55
|
-
},
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
return resp.json()
|
|
59
|
-
},
|
|
60
|
-
onSuccess() {
|
|
61
|
-
if (!props.onDataChanged) return
|
|
62
|
-
props.onDataChanged()
|
|
63
|
-
},
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const handleDeleteClick = (filePath: string) => {
|
|
68
|
-
if (deleteConfirmFiles.has(filePath)) {
|
|
69
|
-
deleteFileMutation.mutate(filePath)
|
|
70
|
-
setDeleteConfirmFiles(new Set())
|
|
71
|
-
} else {
|
|
72
|
-
setDeleteConfirmFiles(new Set([filePath]))
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const handleArchiveClick = (filePath: string) => {
|
|
77
|
-
archiveFileMutation.mutate(filePath)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<div className="flex items-center justify-between">
|
|
82
|
-
<Link
|
|
83
|
-
to="/$"
|
|
84
|
-
params={{ _splat: normalizePath(props.file.path.path) }}
|
|
85
|
-
className="text-blue-600 hover:underline"
|
|
86
|
-
>
|
|
87
|
-
{props.file.path.name}
|
|
88
|
-
</Link>
|
|
89
|
-
<div className="flex items-center gap-2">
|
|
90
|
-
<span className="text-sm uppercase opacity-50">
|
|
91
|
-
{props.file.extension}
|
|
92
|
-
</span>
|
|
93
|
-
<div className="flex gap-1">
|
|
94
|
-
<Button
|
|
95
|
-
size="sm"
|
|
96
|
-
variant="ghost"
|
|
97
|
-
onClick={() => handleArchiveClick(props.file.path.path)}
|
|
98
|
-
disabled={archiveFileMutation.isPending}
|
|
99
|
-
className="h-8 w-8 p-0"
|
|
100
|
-
title="アーカイブする"
|
|
101
|
-
>
|
|
102
|
-
<Archive className="h-4 w-4" />
|
|
103
|
-
</Button>
|
|
104
|
-
<Button
|
|
105
|
-
size="sm"
|
|
106
|
-
variant={
|
|
107
|
-
deleteConfirmFiles.has(props.file.path.path) ? "destructive" : "ghost"
|
|
108
|
-
}
|
|
109
|
-
onClick={() => handleDeleteClick(props.file.path.path)}
|
|
110
|
-
disabled={deleteFileMutation.isPending}
|
|
111
|
-
className="h-8 w-8 p-0"
|
|
112
|
-
title="削除する"
|
|
113
|
-
>
|
|
114
|
-
<Trash2 className="h-4 w-4" />
|
|
115
|
-
</Button>
|
|
116
|
-
</div>
|
|
117
|
-
</div>
|
|
118
|
-
</div>
|
|
119
|
-
)
|
|
120
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
FileIcon,
|
|
3
|
-
FileJsonIcon,
|
|
4
|
-
FileSpreadsheetIcon,
|
|
5
|
-
FileTextIcon,
|
|
6
|
-
} from "lucide-react"
|
|
7
|
-
|
|
8
|
-
type Props = {
|
|
9
|
-
fileName: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function FileTreeIcon(props: Props) {
|
|
13
|
-
if (props.fileName.endsWith(".md")) {
|
|
14
|
-
return <FileTextIcon size={16} className="mr-2 text-green-400" />
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (props.fileName.endsWith(".csv")) {
|
|
18
|
-
return <FileSpreadsheetIcon size={16} className="mr-2 text-purple-400" />
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (props.fileName.endsWith(".json")) {
|
|
22
|
-
return <FileJsonIcon size={16} className="mr-2 text-yellow-400" />
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return <FileIcon size={16} className="mr-2 text-blue-400" />
|
|
26
|
-
}
|