@assistkick/create 1.7.0 → 1.8.0
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/dist/bin/create.js +0 -0
- package/package.json +9 -7
- package/templates/assistkick-product-system/.env.example +1 -0
- package/templates/assistkick-product-system/local.db +0 -0
- package/templates/assistkick-product-system/package.json +4 -2
- package/templates/assistkick-product-system/packages/backend/package.json +2 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/agents.ts +165 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/files.test.ts +358 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/files.ts +356 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/git.ts +96 -1
- package/templates/assistkick-product-system/packages/backend/src/routes/graph.ts +1 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/kanban.ts +43 -4
- package/templates/assistkick-product-system/packages/backend/src/routes/pipeline.ts +200 -84
- package/templates/assistkick-product-system/packages/backend/src/routes/projects.ts +6 -3
- package/templates/assistkick-product-system/packages/backend/src/routes/terminal.ts +53 -17
- package/templates/assistkick-product-system/packages/backend/src/routes/video.ts +218 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/workflow_groups.ts +119 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/workflows.ts +154 -0
- package/templates/assistkick-product-system/packages/backend/src/server.ts +81 -9
- package/templates/assistkick-product-system/packages/backend/src/services/agent_service.test.ts +489 -0
- package/templates/assistkick-product-system/packages/backend/src/services/agent_service.ts +416 -0
- package/templates/assistkick-product-system/packages/backend/src/services/bundle_service.test.ts +189 -0
- package/templates/assistkick-product-system/packages/backend/src/services/bundle_service.ts +182 -0
- package/templates/assistkick-product-system/packages/backend/src/services/init.ts +28 -78
- package/templates/assistkick-product-system/packages/backend/src/services/project_service.test.ts +16 -0
- package/templates/assistkick-product-system/packages/backend/src/services/project_service.ts +73 -2
- package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.test.ts +4 -4
- package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.ts +87 -11
- package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.test.ts +210 -69
- package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.ts +210 -215
- package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.test.ts +162 -0
- package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.ts +148 -0
- package/templates/assistkick-product-system/packages/backend/src/services/terminal_ws_handler.ts +11 -5
- package/templates/assistkick-product-system/packages/backend/src/services/tts_service.test.ts +64 -0
- package/templates/assistkick-product-system/packages/backend/src/services/tts_service.ts +134 -0
- package/templates/assistkick-product-system/packages/backend/src/services/video_render_service.test.ts +256 -0
- package/templates/assistkick-product-system/packages/backend/src/services/video_render_service.ts +258 -0
- package/templates/assistkick-product-system/packages/backend/src/services/workflow_group_service.ts +106 -0
- package/templates/assistkick-product-system/packages/backend/src/services/workflow_service.test.ts +275 -0
- package/templates/assistkick-product-system/packages/backend/src/services/workflow_service.ts +222 -0
- package/templates/assistkick-product-system/packages/frontend/package-lock.json +3455 -0
- package/templates/assistkick-product-system/packages/frontend/package.json +6 -0
- package/templates/assistkick-product-system/packages/frontend/src/App.tsx +8 -0
- package/templates/assistkick-product-system/packages/frontend/src/api/client.ts +456 -16
- package/templates/assistkick-product-system/packages/frontend/src/api/client_files.test.ts +172 -0
- package/templates/assistkick-product-system/packages/frontend/src/api/client_video.test.ts +238 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/AgentsView.tsx +307 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/CoherenceView.tsx +82 -66
- package/templates/assistkick-product-system/packages/frontend/src/components/CompositionPlaceholder.tsx +97 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/DesignSystemView.tsx +20 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/EditorTabBar.tsx +57 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/FileTree.tsx +313 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/FileTreeContextMenu.tsx +61 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/FileTreeInlineInput.tsx +73 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/FilesView.tsx +404 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/GitRepoModal.tsx +187 -56
- package/templates/assistkick-product-system/packages/frontend/src/components/GraphLegend.tsx +71 -73
- package/templates/assistkick-product-system/packages/frontend/src/components/GraphSettings.tsx +8 -8
- package/templates/assistkick-product-system/packages/frontend/src/components/GraphView.tsx +1 -1
- package/templates/assistkick-product-system/packages/frontend/src/components/InviteUserDialog.tsx +15 -11
- package/templates/assistkick-product-system/packages/frontend/src/components/KanbanView.tsx +202 -171
- package/templates/assistkick-product-system/packages/frontend/src/components/LoginPage.tsx +14 -14
- package/templates/assistkick-product-system/packages/frontend/src/components/ProjectSelector.tsx +54 -33
- package/templates/assistkick-product-system/packages/frontend/src/components/QaIssueSheet.tsx +32 -49
- package/templates/assistkick-product-system/packages/frontend/src/components/SidePanel.tsx +43 -48
- package/templates/assistkick-product-system/packages/frontend/src/components/TerminalView.tsx +121 -52
- package/templates/assistkick-product-system/packages/frontend/src/components/Toolbar.tsx +20 -14
- package/templates/assistkick-product-system/packages/frontend/src/components/UsersView.tsx +52 -52
- package/templates/assistkick-product-system/packages/frontend/src/components/VideoGallery.tsx +313 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/VideographyView.tsx +250 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/WorkflowsView.tsx +474 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/AccentBorderList.tsx +53 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/Button.tsx +87 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/ButtonGroup.tsx +29 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/ButtonShowcase.tsx +221 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/CardGlass.tsx +141 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/CompletionRing.tsx +30 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/ContentCard.tsx +34 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/IconButton.tsx +74 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/KanbanCard.tsx +103 -87
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/KanbanCardShowcase.tsx +9 -188
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/Kbd.tsx +11 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/KindBadge.tsx +21 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/NavBarSidekick.tsx +81 -37
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/SidePanelShowcase.tsx +370 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/SideSheet.tsx +64 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ds/StatusDot.tsx +18 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/CheckCardPositionNode.tsx +36 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/CheckCycleCountNode.tsx +60 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/EndNode.tsx +42 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/GroupNode.tsx +189 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/NodePalette.tsx +123 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/RunAgentNode.tsx +51 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/SetCardMetadataNode.tsx +53 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/StartNode.tsx +18 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/TransitionCardNode.tsx +59 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowCanvas.tsx +335 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowMonitorModal.tsx +634 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/autoLayout.ts +103 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/edgeColors.ts +35 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/monitor_nodes.tsx +208 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/workflow_types.test.ts +119 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/workflow_types.ts +107 -0
- package/templates/assistkick-product-system/packages/frontend/src/constants/graph.ts +13 -11
- package/templates/assistkick-product-system/packages/frontend/src/hooks/useAutoSave.ts +75 -0
- package/templates/assistkick-product-system/packages/frontend/src/hooks/useToast.tsx +16 -3
- package/templates/assistkick-product-system/packages/frontend/src/pages/accept_invitation_page.tsx +30 -27
- package/templates/assistkick-product-system/packages/frontend/src/pages/forgot_password_page.tsx +18 -15
- package/templates/assistkick-product-system/packages/frontend/src/pages/register_page.tsx +21 -18
- package/templates/assistkick-product-system/packages/frontend/src/pages/reset_password_page.tsx +28 -25
- package/templates/assistkick-product-system/packages/frontend/src/routes/AgentsRoute.tsx +6 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/CoherenceRoute.tsx +1 -1
- package/templates/assistkick-product-system/packages/frontend/src/routes/DashboardLayout.tsx +2 -2
- package/templates/assistkick-product-system/packages/frontend/src/routes/FilesRoute.tsx +13 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/GraphRoute.tsx +2 -2
- package/templates/assistkick-product-system/packages/frontend/src/routes/VideographyRoute.tsx +13 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/WorkflowsRoute.tsx +6 -0
- package/templates/assistkick-product-system/packages/frontend/src/stores/useProjectStore.ts +6 -3
- package/templates/assistkick-product-system/packages/frontend/src/stores/useSidePanelStore.ts +4 -4
- package/templates/assistkick-product-system/packages/frontend/src/styles/index.css +275 -3535
- package/templates/assistkick-product-system/packages/frontend/src/utils/auto_save_service.test.ts +167 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/auto_save_service.ts +101 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/composition_matcher.test.ts +42 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/composition_matcher.ts +17 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/file_utils.test.ts +145 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/file_utils.ts +42 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/task_status.test.ts +4 -10
- package/templates/assistkick-product-system/packages/frontend/src/utils/task_status.ts +19 -1
- package/templates/assistkick-product-system/packages/frontend/vite.config.ts +5 -0
- package/templates/assistkick-product-system/packages/shared/db/local.db +0 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0004_tidy_matthew_murdock.sql +9 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0005_mysterious_falcon.sql +692 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0006_next_venom.sql +9 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0007_deep_barracuda.sql +39 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0008_puzzling_hannibal_king.sql +1 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0009_amused_beast.sql +8 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0010_spotty_moira_mactaggert.sql +9 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0011_goofy_snowbird.sql +3 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0011_supreme_doctor_octopus.sql +3 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0013_reflective_prowler.sql +15 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0004_snapshot.json +921 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0005_snapshot.json +1042 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0006_snapshot.json +1101 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0007_snapshot.json +1336 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0008_snapshot.json +1275 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0009_snapshot.json +1327 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0010_snapshot.json +1393 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0011_snapshot.json +1436 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0013_snapshot.json +1538 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/_journal.json +70 -0
- package/templates/assistkick-product-system/packages/shared/db/schema.ts +113 -0
- package/templates/assistkick-product-system/packages/shared/lib/claude-service.ts +32 -7
- package/templates/assistkick-product-system/packages/shared/lib/constants.ts +9 -0
- package/templates/assistkick-product-system/packages/shared/lib/git_workflow.ts +12 -4
- package/templates/assistkick-product-system/packages/shared/lib/graph.ts +5 -0
- package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.test.ts +1753 -0
- package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.ts +1281 -0
- package/templates/assistkick-product-system/packages/shared/lib/workflow_orchestrator.ts +211 -0
- package/templates/assistkick-product-system/packages/shared/tools/add_node.test.ts +43 -0
- package/templates/assistkick-product-system/packages/shared/tools/add_node.ts +13 -2
- package/templates/assistkick-product-system/packages/shared/tools/get_kanban.ts +1 -1
- package/templates/assistkick-product-system/packages/shared/tools/migrate_epics.test.ts +226 -0
- package/templates/assistkick-product-system/packages/shared/tools/migrate_epics.ts +251 -0
- package/templates/assistkick-product-system/packages/shared/tools/update_node.ts +2 -2
- package/templates/assistkick-product-system/packages/shared/utils/hello_workflow.test.ts +10 -0
- package/templates/assistkick-product-system/packages/shared/utils/hello_workflow.ts +6 -0
- package/templates/assistkick-product-system/packages/video/Root.tsx +85 -0
- package/templates/assistkick-product-system/packages/video/components/email_scene.tsx +231 -0
- package/templates/assistkick-product-system/packages/video/components/outro_scene.tsx +153 -0
- package/templates/assistkick-product-system/packages/video/components/part_divider.tsx +90 -0
- package/templates/assistkick-product-system/packages/video/components/scene.tsx +226 -0
- package/templates/assistkick-product-system/packages/video/components/theme.ts +22 -0
- package/templates/assistkick-product-system/packages/video/components/title_scene.tsx +169 -0
- package/templates/assistkick-product-system/packages/video/components/video_split_layout.tsx +84 -0
- package/templates/assistkick-product-system/packages/video/compositions/.gitkeep +0 -0
- package/templates/assistkick-product-system/packages/video/index.ts +4 -0
- package/templates/assistkick-product-system/packages/video/package.json +28 -0
- package/templates/assistkick-product-system/packages/video/remotion.config.ts +11 -0
- package/templates/assistkick-product-system/packages/video/scripts/process_script.test.ts +326 -0
- package/templates/assistkick-product-system/packages/video/scripts/process_script.ts +630 -0
- package/templates/assistkick-product-system/packages/video/style.css +1 -0
- package/templates/assistkick-product-system/packages/video/tsconfig.json +18 -0
- package/templates/assistkick-product-system/tests/graph_legend.test.ts +2 -1
- package/templates/assistkick-product-system/tests/video_render_service.test.ts +179 -0
- package/templates/assistkick-product-system/tests/web_terminal.test.ts +219 -455
- package/templates/assistkick-product-system/tests/workflow_integration.test.ts +341 -0
- package/templates/skills/assistkick-developer/SKILL.md +3 -0
- package/templates/skills/assistkick-developer/references/react_development_guidelines.md +225 -0
- package/templates/skills/product-system/graph.json +1890 -0
- package/templates/skills/product-system/kanban.json +304 -0
- package/templates/skills/product-system/nodes/comp_001.md +56 -0
- package/templates/skills/product-system/nodes/comp_002.md +57 -0
- package/templates/skills/product-system/nodes/data_001.md +51 -0
- package/templates/skills/product-system/nodes/data_002.md +40 -0
- package/templates/skills/product-system/nodes/data_004.md +38 -0
- package/templates/skills/product-system/nodes/dec_001.md +34 -0
- package/templates/skills/product-system/nodes/dec_016.md +32 -0
- package/templates/skills/product-system/nodes/feat_008.md +30 -0
- package/templates/skills/video-composition-agent/SKILL.md +232 -0
- package/templates/skills/video-script-writer/SKILL.md +136 -0
package/templates/assistkick-product-system/packages/frontend/src/components/ds/ButtonShowcase.tsx
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { Play, Copy, Settings, Plus, Trash2, AlertTriangle, Check, ArrowRight, Download, ExternalLink } from 'lucide-react';
|
|
2
|
+
import { Button } from './Button';
|
|
3
|
+
import { IconButton } from './IconButton';
|
|
4
|
+
import { ButtonGroup } from './ButtonGroup';
|
|
5
|
+
|
|
6
|
+
/* ── Component ── */
|
|
7
|
+
|
|
8
|
+
export const ButtonShowcase = () => {
|
|
9
|
+
return (
|
|
10
|
+
<div>
|
|
11
|
+
{/* ─── Primary ─── */}
|
|
12
|
+
<h4 className="mb-3 text-[11px] font-bold uppercase tracking-widest text-content-muted">
|
|
13
|
+
Primary
|
|
14
|
+
</h4>
|
|
15
|
+
<p className="mb-4 text-[12px] text-content-muted">
|
|
16
|
+
Accent fill with glow. Use for the main call-to-action per view.
|
|
17
|
+
</p>
|
|
18
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
19
|
+
<Button variant="primary" icon={<Plus size={14} strokeWidth={2} />}>
|
|
20
|
+
Create Feature
|
|
21
|
+
</Button>
|
|
22
|
+
<Button variant="primary">
|
|
23
|
+
Save Changes
|
|
24
|
+
</Button>
|
|
25
|
+
<Button variant="primary" disabled>
|
|
26
|
+
Disabled
|
|
27
|
+
</Button>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
{/* ─── Secondary / Outline ─── */}
|
|
31
|
+
<h4 className="mb-3 mt-8 text-[11px] font-bold uppercase tracking-widest text-content-muted">
|
|
32
|
+
Secondary (Outline)
|
|
33
|
+
</h4>
|
|
34
|
+
<p className="mb-4 text-[12px] text-content-muted">
|
|
35
|
+
Transparent with accent border. Fills on hover. Use alongside primary or for secondary actions.
|
|
36
|
+
</p>
|
|
37
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
38
|
+
<Button variant="secondary" icon={<ArrowRight size={14} strokeWidth={2} />}>
|
|
39
|
+
Continue
|
|
40
|
+
</Button>
|
|
41
|
+
<Button variant="secondary">
|
|
42
|
+
Sign In
|
|
43
|
+
</Button>
|
|
44
|
+
<Button variant="secondary" disabled>
|
|
45
|
+
Disabled
|
|
46
|
+
</Button>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
{/* ─── Ghost ─── */}
|
|
50
|
+
<h4 className="mb-3 mt-8 text-[11px] font-bold uppercase tracking-widest text-content-muted">
|
|
51
|
+
Ghost
|
|
52
|
+
</h4>
|
|
53
|
+
<p className="mb-4 text-[12px] text-content-muted">
|
|
54
|
+
Transparent with subtle border. Use for toolbar actions, settings, and low-emphasis controls.
|
|
55
|
+
</p>
|
|
56
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
57
|
+
<Button variant="ghost" icon={<Settings size={14} strokeWidth={2} />}>
|
|
58
|
+
Settings
|
|
59
|
+
</Button>
|
|
60
|
+
<Button variant="ghost" icon={<Download size={14} strokeWidth={2} />}>
|
|
61
|
+
Export
|
|
62
|
+
</Button>
|
|
63
|
+
<Button variant="ghost">
|
|
64
|
+
Cancel
|
|
65
|
+
</Button>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
{/* ─── Danger ─── */}
|
|
69
|
+
<h4 className="mb-3 mt-8 text-[11px] font-bold uppercase tracking-widest text-content-muted">
|
|
70
|
+
Danger
|
|
71
|
+
</h4>
|
|
72
|
+
<p className="mb-4 text-[12px] text-content-muted">
|
|
73
|
+
Dashed error border. Fills on hover. Use for destructive or irreversible actions.
|
|
74
|
+
</p>
|
|
75
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
76
|
+
<Button variant="danger" icon={<Trash2 size={14} strokeWidth={2} />}>
|
|
77
|
+
Delete
|
|
78
|
+
</Button>
|
|
79
|
+
<Button variant="danger" icon={<AlertTriangle size={14} strokeWidth={2} />}>
|
|
80
|
+
Unblock
|
|
81
|
+
</Button>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
{/* ─── Icon Buttons ─── */}
|
|
85
|
+
<h4 className="mb-3 mt-8 text-[11px] font-bold uppercase tracking-widest text-content-muted">
|
|
86
|
+
Icon Buttons
|
|
87
|
+
</h4>
|
|
88
|
+
<p className="mb-4 text-[12px] text-content-muted">
|
|
89
|
+
Square icon-only buttons for compact controls. Available in multiple sizes and variants.
|
|
90
|
+
</p>
|
|
91
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
92
|
+
<div className="flex flex-col items-center gap-1.5">
|
|
93
|
+
<IconButton label="Settings" size="lg">
|
|
94
|
+
<Settings size={18} strokeWidth={2} />
|
|
95
|
+
</IconButton>
|
|
96
|
+
<span className="text-[10px] text-content-muted">lg</span>
|
|
97
|
+
</div>
|
|
98
|
+
<div className="flex flex-col items-center gap-1.5">
|
|
99
|
+
<IconButton label="Settings" size="md">
|
|
100
|
+
<Settings size={14} strokeWidth={2} />
|
|
101
|
+
</IconButton>
|
|
102
|
+
<span className="text-[10px] text-content-muted">md</span>
|
|
103
|
+
</div>
|
|
104
|
+
<div className="flex flex-col items-center gap-1.5">
|
|
105
|
+
<IconButton label="Copy" size="sm">
|
|
106
|
+
<Copy size={12} strokeWidth={2} />
|
|
107
|
+
</IconButton>
|
|
108
|
+
<span className="text-[10px] text-content-muted">sm</span>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div className="mx-2 h-8 w-px bg-edge" />
|
|
112
|
+
|
|
113
|
+
<div className="flex flex-col items-center gap-1.5">
|
|
114
|
+
<IconButton label="Add" variant="accent">
|
|
115
|
+
<Plus size={14} strokeWidth={2} />
|
|
116
|
+
</IconButton>
|
|
117
|
+
<span className="text-[10px] text-content-muted">accent</span>
|
|
118
|
+
</div>
|
|
119
|
+
<div className="flex flex-col items-center gap-1.5">
|
|
120
|
+
<IconButton label="Play" variant="accent" shape="circle">
|
|
121
|
+
<Play size={12} strokeWidth={2} fill="currentColor" />
|
|
122
|
+
</IconButton>
|
|
123
|
+
<span className="text-[10px] text-content-muted">circle</span>
|
|
124
|
+
</div>
|
|
125
|
+
<div className="flex flex-col items-center gap-1.5">
|
|
126
|
+
<IconButton label="Delete" variant="danger">
|
|
127
|
+
<Trash2 size={14} strokeWidth={2} />
|
|
128
|
+
</IconButton>
|
|
129
|
+
<span className="text-[10px] text-content-muted">danger</span>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
{/* ─── Sizes ─── */}
|
|
134
|
+
<h4 className="mb-3 mt-8 text-[11px] font-bold uppercase tracking-widest text-content-muted">
|
|
135
|
+
Sizes
|
|
136
|
+
</h4>
|
|
137
|
+
<p className="mb-4 text-[12px] text-content-muted">
|
|
138
|
+
Three sizes for different contexts. Small for inline/card controls, medium for standard actions, large for hero CTAs.
|
|
139
|
+
</p>
|
|
140
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
141
|
+
<div className="flex flex-col items-center gap-1.5">
|
|
142
|
+
<Button variant="primary" size="sm" icon={<Check size={12} strokeWidth={2} />}>
|
|
143
|
+
Small
|
|
144
|
+
</Button>
|
|
145
|
+
<span className="text-[10px] text-content-muted">sm · 28px</span>
|
|
146
|
+
</div>
|
|
147
|
+
<div className="flex flex-col items-center gap-1.5">
|
|
148
|
+
<Button variant="primary" size="md" icon={<Check size={14} strokeWidth={2} />}>
|
|
149
|
+
Medium
|
|
150
|
+
</Button>
|
|
151
|
+
<span className="text-[10px] text-content-muted">md · 36px</span>
|
|
152
|
+
</div>
|
|
153
|
+
<div className="flex flex-col items-center gap-1.5">
|
|
154
|
+
<Button variant="primary" size="lg" icon={<Check size={16} strokeWidth={2} />}>
|
|
155
|
+
Large
|
|
156
|
+
</Button>
|
|
157
|
+
<span className="text-[10px] text-content-muted">lg · 44px</span>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
{/* ─── Button Group ─── */}
|
|
162
|
+
<h4 className="mb-3 mt-8 text-[11px] font-bold uppercase tracking-widest text-content-muted">
|
|
163
|
+
Button Group
|
|
164
|
+
</h4>
|
|
165
|
+
<p className="mb-4 text-[12px] text-content-muted">
|
|
166
|
+
Related actions grouped with merged borders.
|
|
167
|
+
</p>
|
|
168
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
169
|
+
<ButtonGroup>
|
|
170
|
+
<button>Board</button>
|
|
171
|
+
<button className="bg-accent/10 font-semibold text-accent">List</button>
|
|
172
|
+
<button>Timeline</button>
|
|
173
|
+
</ButtonGroup>
|
|
174
|
+
|
|
175
|
+
<div className="mx-2 h-8 w-px bg-edge" />
|
|
176
|
+
|
|
177
|
+
<ButtonGroup>
|
|
178
|
+
<button className="flex items-center gap-1.5">
|
|
179
|
+
<Copy size={12} strokeWidth={2} />
|
|
180
|
+
Copy
|
|
181
|
+
</button>
|
|
182
|
+
<button className="flex items-center gap-1.5">
|
|
183
|
+
<Download size={12} strokeWidth={2} />
|
|
184
|
+
Export
|
|
185
|
+
</button>
|
|
186
|
+
<button className="flex items-center gap-1.5">
|
|
187
|
+
<ExternalLink size={12} strokeWidth={2} />
|
|
188
|
+
Share
|
|
189
|
+
</button>
|
|
190
|
+
</ButtonGroup>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
{/* ─── States ─── */}
|
|
194
|
+
<h4 className="mb-3 mt-8 text-[11px] font-bold uppercase tracking-widest text-content-muted">
|
|
195
|
+
Interactive States
|
|
196
|
+
</h4>
|
|
197
|
+
<p className="mb-4 text-[12px] text-content-muted">
|
|
198
|
+
All buttons follow the same state pattern: default, hover (brighter/fill), active (pressed), disabled (50% opacity).
|
|
199
|
+
</p>
|
|
200
|
+
<div className="grid grid-cols-2 gap-4 sm:grid-cols-4">
|
|
201
|
+
{([
|
|
202
|
+
{ state: 'Default', extraClass: '' },
|
|
203
|
+
{ state: 'Hover', extraClass: 'brightness-110' },
|
|
204
|
+
{ state: 'Active', extraClass: 'brightness-90' },
|
|
205
|
+
{ state: 'Disabled', extraClass: '', disabled: true },
|
|
206
|
+
] as const).map(({ state, extraClass, ...rest }) => (
|
|
207
|
+
<div key={state} className="rounded-xl border border-edge px-4 py-3 text-center">
|
|
208
|
+
<Button
|
|
209
|
+
variant="primary"
|
|
210
|
+
className={extraClass}
|
|
211
|
+
disabled={'disabled' in rest}
|
|
212
|
+
>
|
|
213
|
+
Action
|
|
214
|
+
</Button>
|
|
215
|
+
<div className="mt-2 text-[10px] text-content-muted">{state}</div>
|
|
216
|
+
</div>
|
|
217
|
+
))}
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
);
|
|
221
|
+
};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Play, AlertTriangle, Lock, CircleDot, Copy,
|
|
3
|
+
} from 'lucide-react';
|
|
4
|
+
import { KindBadge } from './KindBadge';
|
|
5
|
+
|
|
6
|
+
/* ── Types ── */
|
|
7
|
+
|
|
8
|
+
export interface DemoCard {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
pct: number;
|
|
12
|
+
kind: 'new' | 'improvement' | 'bugfix';
|
|
13
|
+
rejections: number;
|
|
14
|
+
pipeline: 'idle' | 'active' | 'completed' | 'failed' | 'interrupted' | 'blocked';
|
|
15
|
+
blocked: boolean;
|
|
16
|
+
issues: number;
|
|
17
|
+
stage: 'in_progress' | 'in_review' | 'qa';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
card: DemoCard;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* ── Pipeline helpers ── */
|
|
25
|
+
|
|
26
|
+
const pipelineStyle = (status: DemoCard['pipeline']): string => {
|
|
27
|
+
switch (status) {
|
|
28
|
+
case 'active': return 'bg-accent/10 text-accent animate-pulse';
|
|
29
|
+
case 'completed': return 'bg-emerald-500/10 text-emerald-400';
|
|
30
|
+
case 'failed': return 'bg-error/10 text-error';
|
|
31
|
+
case 'blocked': return 'bg-error/10 text-error';
|
|
32
|
+
case 'interrupted': return 'bg-amber-500/10 text-amber-400';
|
|
33
|
+
default: return '';
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const pipelineLabel = (status: DemoCard['pipeline'], rejections: number): string => {
|
|
38
|
+
if (rejections >= 1 && status !== 'idle') return `Retry ${rejections + 1}`;
|
|
39
|
+
switch (status) {
|
|
40
|
+
case 'active': return 'Running...';
|
|
41
|
+
case 'completed': return 'Completed';
|
|
42
|
+
case 'failed': return 'Failed';
|
|
43
|
+
case 'blocked': return 'Blocked';
|
|
44
|
+
case 'interrupted': return 'Interrupted';
|
|
45
|
+
default: return '';
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/* ── Component ── */
|
|
50
|
+
|
|
51
|
+
export const CardGlass = ({ card }: Props) => {
|
|
52
|
+
const hasPipeline = card.pipeline !== 'idle';
|
|
53
|
+
const hasStatusRow = card.rejections > 0 || hasPipeline;
|
|
54
|
+
const stripColor = card.blocked
|
|
55
|
+
? 'from-error/60 to-error/20'
|
|
56
|
+
: card.rejections >= 3
|
|
57
|
+
? 'from-error/40 to-amber-500/20'
|
|
58
|
+
: card.pipeline === 'active'
|
|
59
|
+
? 'from-accent/60 to-accent/20'
|
|
60
|
+
: card.pipeline === 'completed'
|
|
61
|
+
? 'from-emerald-400/60 to-emerald-400/20'
|
|
62
|
+
: 'from-edge to-transparent';
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div className="group relative overflow-hidden rounded-2xl bg-surface border border-edge shadow-lg shadow-black/10 backdrop-blur-sm transition-all duration-200 hover:border-content/15 hover:shadow-xl hover:shadow-black/15">
|
|
66
|
+
<div className={`absolute left-0 top-0 h-full w-1 bg-gradient-to-b ${stripColor}`} />
|
|
67
|
+
<div className="p-5 pl-6">
|
|
68
|
+
{/* Header */}
|
|
69
|
+
<div className="flex items-center gap-2.5">
|
|
70
|
+
<span className="font-mono text-[12px] text-content-secondary">{card.id}</span>
|
|
71
|
+
<KindBadge kind={card.kind} />
|
|
72
|
+
<button className="flex h-6 w-6 items-center justify-center rounded-md bg-white/[0.08] text-content-secondary transition-colors hover:bg-white/15 hover:text-content cursor-pointer">
|
|
73
|
+
<Copy size={12} strokeWidth={2} />
|
|
74
|
+
</button>
|
|
75
|
+
<div className="flex-1" />
|
|
76
|
+
{card.blocked ? (
|
|
77
|
+
<span className="flex items-center gap-1.5 rounded-full bg-error/15 px-2.5 py-1 text-[11px] font-bold text-error backdrop-blur">
|
|
78
|
+
<Lock size={11} strokeWidth={2.5} /> Blocked
|
|
79
|
+
</span>
|
|
80
|
+
) : card.pipeline === 'idle' ? (
|
|
81
|
+
<button className="flex h-7 w-7 items-center justify-center rounded-full bg-accent/10 text-accent backdrop-blur transition-all hover:bg-accent hover:text-surface hover:shadow-[0_0_12px_-2px_var(--accent)] cursor-pointer">
|
|
82
|
+
<Play size={12} strokeWidth={2.5} fill="currentColor" />
|
|
83
|
+
</button>
|
|
84
|
+
) : null}
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
{/* Name */}
|
|
88
|
+
<div className="mt-3 text-[15px] font-semibold leading-snug text-content">{card.name}</div>
|
|
89
|
+
|
|
90
|
+
{/* Spec disc */}
|
|
91
|
+
<div className="mt-3.5 flex items-center gap-2.5">
|
|
92
|
+
<svg width="24" height="24" viewBox="0 0 24 24" className="shrink-0 -rotate-90">
|
|
93
|
+
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" strokeWidth="2.5" className="text-white/5" />
|
|
94
|
+
<circle
|
|
95
|
+
cx="12" cy="12" r="10" fill="none" strokeWidth="2.5"
|
|
96
|
+
stroke="url(#specGrad)" strokeLinecap="round"
|
|
97
|
+
strokeDasharray={`${(card.pct / 100) * 2 * Math.PI * 10} ${2 * Math.PI * 10}`}
|
|
98
|
+
/>
|
|
99
|
+
<defs>
|
|
100
|
+
<linearGradient id="specGrad" x1="0" y1="0" x2="1" y2="1">
|
|
101
|
+
<stop offset="0%" stopColor="var(--completeness-fill)" />
|
|
102
|
+
<stop offset="100%" stopColor="var(--accent)" stopOpacity="0.6" />
|
|
103
|
+
</linearGradient>
|
|
104
|
+
</defs>
|
|
105
|
+
</svg>
|
|
106
|
+
<span className="font-mono text-[12px] text-content-secondary">{card.pct}%</span>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
{/* Status pills */}
|
|
110
|
+
{hasStatusRow && (
|
|
111
|
+
<div className="mt-3.5">
|
|
112
|
+
<div className="flex gap-1.5">
|
|
113
|
+
{card.rejections > 0 && (
|
|
114
|
+
<span className="flex-1 rounded-full bg-amber-400/15 py-1 text-center text-[11px] font-semibold text-amber-400 backdrop-blur">
|
|
115
|
+
{card.rejections}x rejected
|
|
116
|
+
</span>
|
|
117
|
+
)}
|
|
118
|
+
{hasPipeline && (
|
|
119
|
+
<span className={`flex-1 inline-flex items-center justify-center gap-1.5 rounded-full py-1 text-[11px] font-semibold backdrop-blur ${pipelineStyle(card.pipeline)}`}>
|
|
120
|
+
{card.pipeline === 'active' && <CircleDot size={12} strokeWidth={2.5} />}
|
|
121
|
+
{card.pipeline === 'failed' && <AlertTriangle size={12} strokeWidth={2.5} />}
|
|
122
|
+
{pipelineLabel(card.pipeline, card.rejections)}
|
|
123
|
+
</span>
|
|
124
|
+
)}
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
)}
|
|
128
|
+
|
|
129
|
+
{/* Issues */}
|
|
130
|
+
<button className={[
|
|
131
|
+
'mt-3.5 w-full rounded-full border py-2 text-center text-[12px] font-mono backdrop-blur transition-all cursor-pointer',
|
|
132
|
+
card.issues > 0
|
|
133
|
+
? 'border-white/10 text-content-secondary hover:border-accent/30 hover:text-accent'
|
|
134
|
+
: 'border-white/5 text-content-muted/50 hover:border-white/10 hover:text-content-muted',
|
|
135
|
+
].join(' ')}>
|
|
136
|
+
{card.issues > 0 ? `${card.issues} issue${card.issues !== 1 ? 's' : ''} reported` : 'No issues'}
|
|
137
|
+
</button>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
};
|
package/templates/assistkick-product-system/packages/frontend/src/components/ds/CompletionRing.tsx
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface CompletionRingProps {
|
|
4
|
+
/** Completion percentage as 0–1 fraction */
|
|
5
|
+
pct: number;
|
|
6
|
+
/** Outer diameter in px */
|
|
7
|
+
size?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function CompletionRing({ pct, size = 40 }: CompletionRingProps) {
|
|
11
|
+
const r = (size - 6) / 2;
|
|
12
|
+
const circumference = 2 * Math.PI * r;
|
|
13
|
+
const offset = circumference * (1 - pct);
|
|
14
|
+
return (
|
|
15
|
+
<svg width={size} height={size} className="shrink-0">
|
|
16
|
+
<circle cx={size / 2} cy={size / 2} r={r} fill="none"
|
|
17
|
+
stroke="var(--completeness-bg)" strokeWidth={3} />
|
|
18
|
+
<circle cx={size / 2} cy={size / 2} r={r} fill="none"
|
|
19
|
+
stroke="var(--completeness-fill)" strokeWidth={3}
|
|
20
|
+
strokeDasharray={circumference} strokeDashoffset={offset}
|
|
21
|
+
strokeLinecap="round"
|
|
22
|
+
transform={`rotate(-90 ${size / 2} ${size / 2})`}
|
|
23
|
+
className="transition-all duration-500" />
|
|
24
|
+
<text x={size / 2} y={size / 2} textAnchor="middle" dominantBaseline="central"
|
|
25
|
+
className="fill-content text-[10px] font-bold">
|
|
26
|
+
{Math.round(pct * 100)}%
|
|
27
|
+
</text>
|
|
28
|
+
</svg>
|
|
29
|
+
);
|
|
30
|
+
}
|
package/templates/assistkick-product-system/packages/frontend/src/components/ds/ContentCard.tsx
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { ChevronDown, ChevronRight } from 'lucide-react';
|
|
3
|
+
|
|
4
|
+
export interface ContentCardProps {
|
|
5
|
+
icon: React.ReactNode;
|
|
6
|
+
label: string;
|
|
7
|
+
badge?: React.ReactNode;
|
|
8
|
+
defaultOpen?: boolean;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function ContentCard({ icon, label, badge, defaultOpen = false, children }: ContentCardProps) {
|
|
13
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
14
|
+
return (
|
|
15
|
+
<div className="rounded-xl border border-edge bg-surface-alt overflow-hidden">
|
|
16
|
+
<button
|
|
17
|
+
onClick={() => setOpen(v => !v)}
|
|
18
|
+
className="flex w-full items-center gap-2 px-3 py-2.5 text-left hover:bg-surface-raised/50 transition-colors"
|
|
19
|
+
>
|
|
20
|
+
<span className="text-content-muted shrink-0">{icon}</span>
|
|
21
|
+
<span className="text-[12px] font-medium text-content flex-1">{label}</span>
|
|
22
|
+
{badge}
|
|
23
|
+
{open
|
|
24
|
+
? <ChevronDown size={13} className="text-content-muted" />
|
|
25
|
+
: <ChevronRight size={13} className="text-content-muted" />}
|
|
26
|
+
</button>
|
|
27
|
+
{open && (
|
|
28
|
+
<div className="border-t border-edge px-3 py-3">
|
|
29
|
+
{children}
|
|
30
|
+
</div>
|
|
31
|
+
)}
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
package/templates/assistkick-product-system/packages/frontend/src/components/ds/IconButton.tsx
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
/* ── Types ── */
|
|
4
|
+
|
|
5
|
+
type IconButtonVariant = 'ghost' | 'accent' | 'danger';
|
|
6
|
+
type IconButtonSize = 'sm' | 'md' | 'lg';
|
|
7
|
+
type IconButtonShape = 'square' | 'circle';
|
|
8
|
+
|
|
9
|
+
interface Props extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
10
|
+
variant?: IconButtonVariant;
|
|
11
|
+
size?: IconButtonSize;
|
|
12
|
+
shape?: IconButtonShape;
|
|
13
|
+
/** Accessible label — required since there is no visible text */
|
|
14
|
+
label: string;
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* ── Style maps ── */
|
|
19
|
+
|
|
20
|
+
const variantClasses: Record<IconButtonVariant, string> = {
|
|
21
|
+
ghost: [
|
|
22
|
+
'border border-edge bg-transparent text-content-muted',
|
|
23
|
+
'hover:border-content/20 hover:text-content',
|
|
24
|
+
].join(' '),
|
|
25
|
+
accent: [
|
|
26
|
+
'border border-accent/30 bg-transparent text-accent',
|
|
27
|
+
'hover:bg-accent hover:text-surface',
|
|
28
|
+
].join(' '),
|
|
29
|
+
danger: [
|
|
30
|
+
'border border-dashed border-error bg-transparent text-error',
|
|
31
|
+
'hover:bg-error hover:text-white',
|
|
32
|
+
].join(' '),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const sizeClasses: Record<IconButtonSize, { box: string; radius: Record<IconButtonShape, string> }> = {
|
|
36
|
+
sm: { box: 'h-6 w-6', radius: { square: 'rounded-md', circle: 'rounded-full' } },
|
|
37
|
+
md: { box: 'h-8 w-8', radius: { square: 'rounded-lg', circle: 'rounded-full' } },
|
|
38
|
+
lg: { box: 'h-10 w-10', radius: { square: 'rounded-lg', circle: 'rounded-full' } },
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/* ── Component ── */
|
|
42
|
+
|
|
43
|
+
export const IconButton = ({
|
|
44
|
+
variant = 'ghost',
|
|
45
|
+
size = 'md',
|
|
46
|
+
shape = 'square',
|
|
47
|
+
label,
|
|
48
|
+
disabled,
|
|
49
|
+
className = '',
|
|
50
|
+
children,
|
|
51
|
+
...rest
|
|
52
|
+
}: Props) => {
|
|
53
|
+
const base = 'flex items-center justify-center outline-none cursor-pointer transition-all duration-150';
|
|
54
|
+
const disabledClass = disabled ? 'opacity-50 cursor-not-allowed' : '';
|
|
55
|
+
const sizeConfig = sizeClasses[size];
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<button
|
|
59
|
+
aria-label={label}
|
|
60
|
+
disabled={disabled}
|
|
61
|
+
className={[
|
|
62
|
+
base,
|
|
63
|
+
variantClasses[variant],
|
|
64
|
+
sizeConfig.box,
|
|
65
|
+
sizeConfig.radius[shape],
|
|
66
|
+
disabledClass,
|
|
67
|
+
className,
|
|
68
|
+
].join(' ')}
|
|
69
|
+
{...rest}
|
|
70
|
+
>
|
|
71
|
+
{children}
|
|
72
|
+
</button>
|
|
73
|
+
);
|
|
74
|
+
};
|