blacksmith-cli 0.1.3 → 0.1.5

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 (27) hide show
  1. package/dist/index.js +22 -9
  2. package/dist/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/src/templates/backend/utils/__init__.py.hbs +0 -0
  5. package/src/templates/backend/utils/models.py.hbs +11 -0
  6. package/src/templates/frontend/src/pages/home/home.tsx.hbs +93 -11
  7. package/src/templates/resource/api-hooks/index.ts.hbs +2 -0
  8. package/src/templates/resource/{frontend/hooks → api-hooks}/use-{{kebabs}}-query.ts.hbs +10 -2
  9. package/src/templates/resource/{frontend/hooks → api-hooks}/use-{{kebab}}-mutations.ts.hbs +1 -1
  10. package/src/templates/resource/backend/models.py.hbs +2 -3
  11. package/src/templates/resource/frontend/components/{{kebab}}-card.tsx.hbs +1 -1
  12. package/src/templates/resource/frontend/components/{{kebab}}-list.tsx.hbs +1 -1
  13. package/src/templates/resource/frontend/index.ts.hbs +1 -2
  14. package/src/templates/resource/frontend/pages/{{kebabs}}-page.tsx.hbs +1 -1
  15. package/src/templates/resource/frontend/pages/{{kebab}}-detail-page.tsx.hbs +3 -11
  16. package/src/templates/resource/pages/components/{{kebab}}-card.tsx.hbs +1 -1
  17. package/src/templates/resource/pages/components/{{kebab}}-list.tsx.hbs +1 -1
  18. package/src/templates/resource/pages/hooks/index.ts.hbs +9 -0
  19. package/src/templates/resource/pages/index.ts.hbs +1 -2
  20. package/src/templates/resource/pages/{{kebabs}}-page.tsx.hbs +1 -1
  21. package/src/templates/resource/pages/{{kebab}}-detail-page.tsx.hbs +3 -11
  22. package/src/templates/frontend/src/pages/home/components/features-grid.tsx.hbs +0 -88
  23. package/src/templates/frontend/src/pages/home/components/getting-started.tsx.hbs +0 -88
  24. package/src/templates/frontend/src/pages/home/components/hero-section.tsx.hbs +0 -47
  25. package/src/templates/frontend/src/pages/home/components/resources-section.tsx.hbs +0 -34
  26. package/src/templates/resource/pages/hooks/use-{{kebabs}}-query.ts.hbs +0 -35
  27. package/src/templates/resource/pages/hooks/use-{{kebab}}-mutations.ts.hbs +0 -39
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blacksmith-cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Fullstack Django + React framework — one command, one codebase, one mental model",
5
5
  "type": "module",
6
6
  "bin": {
File without changes
@@ -0,0 +1,11 @@
1
+ import uuid
2
+ from django.db import models
3
+
4
+
5
+ class BaseModel(models.Model):
6
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
7
+ created_at = models.DateTimeField(auto_now_add=True)
8
+ updated_at = models.DateTimeField(auto_now=True)
9
+
10
+ class Meta:
11
+ abstract = True
@@ -1,20 +1,102 @@
1
- import { Stack, Divider } from '@blacksmith-ui/react'
1
+ import {
2
+ Stack,
3
+ Flex,
4
+ Typography,
5
+ Text,
6
+ Button,
7
+ Card,
8
+ CardHeader,
9
+ CardTitle,
10
+ CardDescription,
11
+ CardContent,
12
+ Grid,
13
+ } from '@blacksmith-ui/react'
2
14
  import { useAuth } from '@/features/auth/hooks/use-auth'
3
- import { HeroSection } from './components/hero-section'
4
- import { GettingStarted } from './components/getting-started'
5
- import { FeaturesGrid } from './components/features-grid'
6
- import { ResourcesSection } from './components/resources-section'
15
+ import { Link } from 'react-router-dom'
16
+ import { Path } from '@/router/paths'
17
+ import { BookOpen, Terminal, Layout } from 'lucide-react'
18
+
19
+ const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'
7
20
 
8
21
  export default function HomePage() {
9
22
  const { isAuthenticated } = useAuth()
10
23
 
11
24
  return (
12
- <Stack gap={12}>
13
- <HeroSection isAuthenticated={isAuthenticated} />
14
- <Divider />
15
- <GettingStarted />
16
- <FeaturesGrid />
17
- <ResourcesSection />
25
+ <Stack gap={10} className="pt-16 pb-12">
26
+ <Stack gap={4} align="center">
27
+ <Typography variant="h1" className="sm:text-5xl">
28
+ {{projectName}}
29
+ </Typography>
30
+ <Text size="lg" color="muted" align="center" className="max-w-md">
31
+ Your app is ready. Sign in to get started or explore the API.
32
+ </Text>
33
+ <Flex justify="center" gap="md" className="pt-2">
34
+ {isAuthenticated ? (
35
+ <Button size="lg" asChild>
36
+ <Link to={Path.Dashboard}>Dashboard</Link>
37
+ </Button>
38
+ ) : (
39
+ <Button size="lg" asChild>
40
+ <Link to={Path.Login}>Sign In</Link>
41
+ </Button>
42
+ )}
43
+ <Button variant="outline" size="lg" asChild>
44
+ <a href={`${API_URL}/api/docs/`} target="_blank" rel="noopener noreferrer">
45
+ API Docs
46
+ </a>
47
+ </Button>
48
+ </Flex>
49
+ </Stack>
50
+
51
+ <Grid columns=\{{ base: 1, md: 3 }} gap={4} className="max-w-3xl mx-auto w-full">
52
+ <Card>
53
+ <CardHeader className="pb-2">
54
+ <Flex align="center" gap={2}>
55
+ <Terminal className="h-4 w-4 text-primary" />
56
+ <CardTitle className="text-sm">CLI</CardTitle>
57
+ </Flex>
58
+ </CardHeader>
59
+ <CardContent>
60
+ <CardDescription>
61
+ Run <Text as="code" size="sm" className="font-mono">blacksmith dev</Text> to start the full stack.
62
+ </CardDescription>
63
+ </CardContent>
64
+ </Card>
65
+
66
+ <Card>
67
+ <CardHeader className="pb-2">
68
+ <Flex align="center" gap={2}>
69
+ <BookOpen className="h-4 w-4 text-primary" />
70
+ <CardTitle className="text-sm">API</CardTitle>
71
+ </Flex>
72
+ </CardHeader>
73
+ <CardContent>
74
+ <CardDescription>
75
+ <a href={`${API_URL}/api/docs/`} target="_blank" rel="noopener noreferrer" className="underline underline-offset-4 hover:text-foreground">
76
+ Swagger UI
77
+ </a>
78
+ {' / '}
79
+ <a href={`${API_URL}/admin/`} target="_blank" rel="noopener noreferrer" className="underline underline-offset-4 hover:text-foreground">
80
+ Django Admin
81
+ </a>
82
+ </CardDescription>
83
+ </CardContent>
84
+ </Card>
85
+
86
+ <Card>
87
+ <CardHeader className="pb-2">
88
+ <Flex align="center" gap={2}>
89
+ <Layout className="h-4 w-4 text-primary" />
90
+ <CardTitle className="text-sm">Frontend</CardTitle>
91
+ </Flex>
92
+ </CardHeader>
93
+ <CardContent>
94
+ <CardDescription>
95
+ React, TanStack Query, and Tailwind CSS with typed API hooks.
96
+ </CardDescription>
97
+ </CardContent>
98
+ </Card>
99
+ </Grid>
18
100
  </Stack>
19
101
  )
20
102
  }
@@ -0,0 +1,2 @@
1
+ export { use{{Names}}, useGet{{Name}} } from './use-{{kebabs}}-query'
2
+ export { useCreate{{Name}}, useUpdate{{Name}}, useDelete{{Name}} } from './use-{{kebab}}-mutations'
@@ -1,13 +1,14 @@
1
1
  /**
2
- * use{{Names}} Hook
2
+ * {{Name}} Query Hooks
3
3
  *
4
- * Wraps the generated list query with smart retry and error parsing.
4
+ * List and detail queries with smart retry and error parsing.
5
5
  * Generated by Blacksmith. You own this file — customize as needed.
6
6
  */
7
7
 
8
8
  import { useApiQuery } from '@/shared/hooks/use-api-query'
9
9
  import {
10
10
  {{snakes}}ListOptions,
11
+ {{snakes}}RetrieveOptions,
11
12
  } from '@/api/generated/@tanstack/react-query.gen'
12
13
 
13
14
  interface Use{{Names}}Params {
@@ -33,3 +34,10 @@ export function use{{Names}}(params: Use{{Names}}Params = {}) {
33
34
  }),
34
35
  })
35
36
  }
37
+
38
+ export function useGet{{Name}}(id: string) {
39
+ return useApiQuery({
40
+ ...{{snakes}}RetrieveOptions({ path: { id } }),
41
+ enabled: !!id,
42
+ })
43
+ }
@@ -21,7 +21,7 @@ export function useCreate{{Name}}() {
21
21
  })
22
22
  }
23
23
 
24
- export function useUpdate{{Name}}(id: number) {
24
+ export function useUpdate{{Name}}(id: string) {
25
25
  return useApiMutation({
26
26
  ...{{snakes}}UpdateMutation(),
27
27
  invalidateKeys: [
@@ -1,8 +1,9 @@
1
1
  from django.db import models
2
2
  from django.conf import settings
3
+ from utils.models import BaseModel
3
4
 
4
5
 
5
- class {{Name}}(models.Model):
6
+ class {{Name}}(BaseModel):
6
7
  """{{Name}} model."""
7
8
 
8
9
  title = models.CharField(max_length=255)
@@ -12,8 +13,6 @@ class {{Name}}(models.Model):
12
13
  on_delete=models.CASCADE,
13
14
  related_name='{{snakes}}',
14
15
  )
15
- created_at = models.DateTimeField(auto_now_add=True)
16
- updated_at = models.DateTimeField(auto_now=True)
17
16
 
18
17
  class Meta:
19
18
  ordering = ['-created_at']
@@ -10,7 +10,7 @@ import { Path } from '@/router/paths'
10
10
 
11
11
  interface {{Name}}CardProps {
12
12
  {{name}}: {
13
- id: number
13
+ id: string
14
14
  title: string
15
15
  description?: string
16
16
  created_at: string
@@ -9,7 +9,7 @@ import { {{Name}}Card } from './{{kebab}}-card'
9
9
 
10
10
  interface {{Name}}ListProps {
11
11
  {{names}}: Array<{
12
- id: number
12
+ id: string
13
13
  title: string
14
14
  description?: string
15
15
  created_at: string
@@ -1,6 +1,5 @@
1
1
  export { {{names}}Routes } from './routes'
2
- export { use{{Names}} } from './hooks/use-{{kebabs}}-query'
3
- export { useCreate{{Name}}, useUpdate{{Name}}, useDelete{{Name}} } from './hooks/use-{{kebab}}-mutations'
2
+ export { use{{Names}}, useCreate{{Name}}, useUpdate{{Name}}, useDelete{{Name}} } from '@/api/hooks/{{kebabs}}'
4
3
  export { {{Name}}Card } from './components/{{kebab}}-card'
5
4
  export { {{Name}}List } from './components/{{kebab}}-list'
6
5
  export { {{Name}}Form } from './components/{{kebab}}-form'
@@ -5,7 +5,7 @@
5
5
  * Generated by Blacksmith. You own this file — customize as needed.
6
6
  */
7
7
 
8
- import { use{{Names}} } from '../hooks/use-{{kebabs}}-query'
8
+ import { use{{Names}} } from '@/api/hooks/{{kebabs}}'
9
9
  import { {{Name}}List } from '../components/{{kebab}}-list'
10
10
  import { Alert, AlertDescription } from '@blacksmith-ui/react'
11
11
 
@@ -6,24 +6,16 @@
6
6
  */
7
7
 
8
8
  import { useParams, useNavigate } from 'react-router-dom'
9
- import { useApiQuery } from '@/shared/hooks/use-api-query'
10
- import { useDelete{{Name}} } from '../hooks/use-{{kebab}}-mutations'
9
+ import { useGet{{Name}}, useDelete{{Name}} } from '@/api/hooks/{{kebabs}}'
11
10
  import { Alert, AlertDescription } from '@blacksmith-ui/react'
12
11
  import { Path } from '@/router/paths'
13
- import {
14
- {{snakes}}RetrieveOptions,
15
- } from '@/api/generated/@tanstack/react-query.gen'
16
12
 
17
13
  export default function {{Name}}DetailPage() {
18
14
  const { id } = useParams<{ id: string }>()
19
15
  const navigate = useNavigate()
20
16
  const delete{{Name}} = useDelete{{Name}}()
21
17
 
22
- const { data: {{name}}, isLoading, errorMessage } = useApiQuery({
23
- ...{{snakes}}RetrieveOptions({
24
- path: { id: Number(id) },
25
- }),
26
- })
18
+ const { data: {{name}}, isLoading, errorMessage } = useGet{{Name}}(id!)
27
19
 
28
20
  if (isLoading) {
29
21
  return (
@@ -49,7 +41,7 @@ export default function {{Name}}DetailPage() {
49
41
 
50
42
  const handleDelete = async () => {
51
43
  if (window.confirm('Are you sure you want to delete this {{name}}?')) {
52
- await delete{{Name}}.mutateAsync({ path: { id: Number(id) } })
44
+ await delete{{Name}}.mutateAsync({ path: { id: id! } })
53
45
  navigate(Path.{{Names}})
54
46
  }
55
47
  }
@@ -10,7 +10,7 @@ import { Path } from '@/router/paths'
10
10
 
11
11
  interface {{Name}}CardProps {
12
12
  {{name}}: {
13
- id: number
13
+ id: string
14
14
  title: string
15
15
  description?: string
16
16
  created_at: string
@@ -9,7 +9,7 @@ import { {{Name}}Card } from './{{kebab}}-card'
9
9
 
10
10
  interface {{Name}}ListProps {
11
11
  {{names}}: Array<{
12
- id: number
12
+ id: string
13
13
  title: string
14
14
  description?: string
15
15
  created_at: string
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Page-local hooks for {{Names}}
3
+ *
4
+ * This folder is for hooks that are specific to the {{Names}} page UI logic,
5
+ * such as form state, filtering, pagination, modals, and other page-level concerns.
6
+ *
7
+ * API hooks (queries and mutations) live in @/api/hooks/{{kebabs}}/ and should
8
+ * be imported from there.
9
+ */
@@ -1,6 +1,5 @@
1
1
  export { {{names}}Routes } from './routes'
2
- export { use{{Names}} } from './hooks/use-{{kebabs}}-query'
3
- export { useCreate{{Name}}, useUpdate{{Name}}, useDelete{{Name}} } from './hooks/use-{{kebab}}-mutations'
2
+ export { use{{Names}}, useCreate{{Name}}, useUpdate{{Name}}, useDelete{{Name}} } from '@/api/hooks/{{kebabs}}'
4
3
  export { {{Name}}Card } from './components/{{kebab}}-card'
5
4
  export { {{Name}}List } from './components/{{kebab}}-list'
6
5
  export { {{Name}}Form } from './components/{{kebab}}-form'
@@ -5,7 +5,7 @@
5
5
  * Generated by Blacksmith. You own this file — customize as needed.
6
6
  */
7
7
 
8
- import { use{{Names}} } from './hooks/use-{{kebabs}}-query'
8
+ import { use{{Names}} } from '@/api/hooks/{{kebabs}}'
9
9
  import { {{Name}}List } from './components/{{kebab}}-list'
10
10
  import { Alert, AlertDescription } from '@blacksmith-ui/react'
11
11
 
@@ -6,24 +6,16 @@
6
6
  */
7
7
 
8
8
  import { useParams, useNavigate } from 'react-router-dom'
9
- import { useApiQuery } from '@/shared/hooks/use-api-query'
10
- import { useDelete{{Name}} } from './hooks/use-{{kebab}}-mutations'
9
+ import { useGet{{Name}}, useDelete{{Name}} } from '@/api/hooks/{{kebabs}}'
11
10
  import { Alert, AlertDescription } from '@blacksmith-ui/react'
12
11
  import { Path } from '@/router/paths'
13
- import {
14
- {{snakes}}RetrieveOptions,
15
- } from '@/api/generated/@tanstack/react-query.gen'
16
12
 
17
13
  export default function {{Name}}DetailPage() {
18
14
  const { id } = useParams<{ id: string }>()
19
15
  const navigate = useNavigate()
20
16
  const delete{{Name}} = useDelete{{Name}}()
21
17
 
22
- const { data: {{name}}, isLoading, errorMessage } = useApiQuery({
23
- ...{{snakes}}RetrieveOptions({
24
- path: { id: Number(id) },
25
- }),
26
- })
18
+ const { data: {{name}}, isLoading, errorMessage } = useGet{{Name}}(id!)
27
19
 
28
20
  if (isLoading) {
29
21
  return (
@@ -49,7 +41,7 @@ export default function {{Name}}DetailPage() {
49
41
 
50
42
  const handleDelete = async () => {
51
43
  if (window.confirm('Are you sure you want to delete this {{name}}?')) {
52
- await delete{{Name}}.mutateAsync({ path: { id: Number(id) } })
44
+ await delete{{Name}}.mutateAsync({ path: { id: id! } })
53
45
  navigate(Path.{{Names}})
54
46
  }
55
47
  }
@@ -1,88 +0,0 @@
1
- import {
2
- Card,
3
- CardHeader,
4
- CardTitle,
5
- CardDescription,
6
- CardContent,
7
- Badge,
8
- Stack,
9
- Flex,
10
- Grid,
11
- Typography,
12
- Text,
13
- } from '@blacksmith-ui/react'
14
- import { Database, Layout, Shield, Code2, Zap, Rocket } from 'lucide-react'
15
-
16
- const features = [
17
- {
18
- icon: Database,
19
- title: 'Django REST API',
20
- description: 'Production-ready backend with JWT auth, serializers, and OpenAPI docs.',
21
- badge: 'Backend',
22
- },
23
- {
24
- icon: Layout,
25
- title: 'React + TypeScript',
26
- description: 'Vite-powered frontend with TanStack Query, React Router, and Tailwind CSS.',
27
- badge: 'Frontend',
28
- },
29
- {
30
- icon: Shield,
31
- title: 'Authentication',
32
- description: 'Complete auth flow with login, register, password reset, and role guards.',
33
- badge: 'Full Stack',
34
- },
35
- {
36
- icon: Code2,
37
- title: 'Type-Safe API',
38
- description: 'Auto-generated TypeScript client from your OpenAPI schema via blacksmith sync.',
39
- badge: 'DX',
40
- },
41
- {
42
- icon: Zap,
43
- title: 'Blacksmith UI',
44
- description: '80+ accessible components, form library, hooks, and dark mode theming.',
45
- badge: 'UI',
46
- },
47
- {
48
- icon: Rocket,
49
- title: 'Developer Experience',
50
- description: 'Hot reload, AI-ready CLAUDE.md, and one command to run the full stack.',
51
- badge: 'DX',
52
- },
53
- ]
54
-
55
- export function FeaturesGrid() {
56
- return (
57
- <Stack as="section" gap={6}>
58
- <Stack gap={2} align="center">
59
- <Typography variant="h2">What's Included</Typography>
60
- <Text color="muted">
61
- A batteries-included stack so you can focus on your product.
62
- </Text>
63
- </Stack>
64
- <Grid columns=\{{ base: 1, sm: 2, lg: 3 }} gap={4}>
65
- {features.map((feature) => (
66
- <Card key={feature.title} className="group transition-colors hover:border-primary/50">
67
- <CardHeader className="pb-3">
68
- <Flex align="start" justify="between">
69
- <Flex align="center" justify="center" className="h-10 w-10 rounded-lg bg-primary/10 transition-colors group-hover:bg-primary/20">
70
- <feature.icon className="h-5 w-5 text-primary" />
71
- </Flex>
72
- <Badge variant="outline" className="text-xs">
73
- {feature.badge}
74
- </Badge>
75
- </Flex>
76
- </CardHeader>
77
- <CardContent>
78
- <Stack gap={1.5}>
79
- <CardTitle className="text-base">{feature.title}</CardTitle>
80
- <CardDescription>{feature.description}</CardDescription>
81
- </Stack>
82
- </CardContent>
83
- </Card>
84
- ))}
85
- </Grid>
86
- </Stack>
87
- )
88
- }
@@ -1,88 +0,0 @@
1
- import {
2
- Card,
3
- CardHeader,
4
- CardTitle,
5
- CardDescription,
6
- CardContent,
7
- Button,
8
- Tooltip,
9
- Stack,
10
- Flex,
11
- Grid,
12
- Typography,
13
- Text,
14
- } from '@blacksmith-ui/react'
15
- import { Terminal, Copy, Check } from 'lucide-react'
16
- import { useCopyToClipboard } from '@blacksmith-ui/hooks'
17
-
18
- const steps = [
19
- {
20
- command: 'blacksmith dev',
21
- title: 'Start the dev server',
22
- description: 'Runs Django, Vite, and OpenAPI watcher concurrently.',
23
- },
24
- {
25
- command: 'blacksmith make:resource Post',
26
- title: 'Scaffold a resource',
27
- description: 'Generates model, serializer, viewset, hooks, and pages.',
28
- },
29
- {
30
- command: 'blacksmith sync',
31
- title: 'Sync API types',
32
- description: 'Regenerates the TypeScript client from your Django schema.',
33
- },
34
- ]
35
-
36
- function CommandBlock({ command }: { command: string }) {
37
- const { status, copy } = useCopyToClipboard(2000)
38
- const copied = status === 'copied'
39
-
40
- return (
41
- <Flex align="center" gap={2} className="rounded-lg bg-muted px-3 py-2">
42
- <Terminal className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
43
- <Text as="code" size="sm" className="flex-1 font-mono">{command}</Text>
44
- <Tooltip content={copied ? 'Copied!' : 'Copy command'}>
45
- <Button variant="ghost" size="icon" className="h-7 w-7" onClick={() => copy(command)}>
46
- {copied ? (
47
- <Check className="h-3.5 w-3.5 text-green-500" />
48
- ) : (
49
- <Copy className="h-3.5 w-3.5" />
50
- )}
51
- </Button>
52
- </Tooltip>
53
- </Flex>
54
- )
55
- }
56
-
57
- export function GettingStarted() {
58
- return (
59
- <Stack as="section" gap={6}>
60
- <Stack gap={2} align="center">
61
- <Typography variant="h2">Get Started in 3 Steps</Typography>
62
- <Text color="muted">
63
- Everything you need to go from scaffold to production.
64
- </Text>
65
- </Stack>
66
- <Grid columns=\{{ base: 1, md: 3 }} gap={4}>
67
- {steps.map((step, index) => (
68
- <Card key={step.command}>
69
- <CardHeader className="pb-3">
70
- <Flex align="center" gap={3}>
71
- <Flex align="center" justify="center" className="h-8 w-8 shrink-0 rounded-full bg-primary text-primary-foreground">
72
- <Text size="sm" weight="semibold">{index + 1}</Text>
73
- </Flex>
74
- <CardTitle className="text-base">{step.title}</CardTitle>
75
- </Flex>
76
- </CardHeader>
77
- <CardContent>
78
- <Stack gap={3}>
79
- <CardDescription>{step.description}</CardDescription>
80
- <CommandBlock command={step.command} />
81
- </Stack>
82
- </CardContent>
83
- </Card>
84
- ))}
85
- </Grid>
86
- </Stack>
87
- )
88
- }
@@ -1,47 +0,0 @@
1
- import { Stack, Flex, Typography, Text, Button } from '@blacksmith-ui/react'
2
- import { Rocket, BookOpen } from 'lucide-react'
3
- import { Link } from 'react-router-dom'
4
- import { Path } from '@/router/paths'
5
-
6
- const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'
7
-
8
- interface HeroSectionProps {
9
- isAuthenticated: boolean
10
- }
11
-
12
- export function HeroSection({ isAuthenticated }: HeroSectionProps) {
13
- return (
14
- <Stack as="section" gap={6} align="center" className="pt-10 pb-2">
15
- <Typography variant="h1" className="sm:text-5xl">
16
- Welcome to{' '}
17
- <Text as="span" color="primary">{{projectName}}</Text>
18
- </Typography>
19
- <Text size="lg" color="muted" align="center" className="max-w-2xl">
20
- Your fullstack Django + React application is ready to go.
21
- </Text>
22
- <Flex justify="center" gap={3} className="pt-2">
23
- {isAuthenticated ? (
24
- <Button size="lg" asChild>
25
- <Link to={Path.Dashboard}>
26
- <Rocket className="mr-2 h-4 w-4" />
27
- Dashboard
28
- </Link>
29
- </Button>
30
- ) : (
31
- <Button size="lg" asChild>
32
- <Link to={Path.Login}>
33
- <Rocket className="mr-2 h-4 w-4" />
34
- Sign In
35
- </Link>
36
- </Button>
37
- )}
38
- <Button variant="outline" size="lg" asChild>
39
- <a href={`${API_URL}/api/docs/`} target="_blank" rel="noopener noreferrer">
40
- <BookOpen className="mr-2 h-4 w-4" />
41
- API Docs
42
- </a>
43
- </Button>
44
- </Flex>
45
- </Stack>
46
- )
47
- }
@@ -1,34 +0,0 @@
1
- import { Stack, Flex, Typography, Text, Button } from '@blacksmith-ui/react'
2
- import { ExternalLink } from 'lucide-react'
3
-
4
- const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'
5
-
6
- const links = [
7
- { label: 'Swagger UI', href: `${API_URL}/api/docs/` },
8
- { label: 'ReDoc', href: `${API_URL}/api/redoc/` },
9
- { label: 'OpenAPI Schema', href: `${API_URL}/api/schema/` },
10
- { label: 'Django Admin', href: `${API_URL}/admin/` },
11
- ]
12
-
13
- export function ResourcesSection() {
14
- return (
15
- <Stack as="section" gap={4}>
16
- <Stack gap={2} align="center">
17
- <Typography variant="h2">Resources</Typography>
18
- <Text color="muted">
19
- Documentation and tools to help you build.
20
- </Text>
21
- </Stack>
22
- <Flex justify="center" wrap="wrap" gap={3}>
23
- {links.map((link) => (
24
- <Button key={link.label} variant="outline" size="sm" asChild>
25
- <a href={link.href} target="_blank" rel="noopener noreferrer">
26
- <ExternalLink className="mr-2 h-3.5 w-3.5" />
27
- {link.label}
28
- </a>
29
- </Button>
30
- ))}
31
- </Flex>
32
- </Stack>
33
- )
34
- }
@@ -1,35 +0,0 @@
1
- /**
2
- * use{{Names}} Hook
3
- *
4
- * Wraps the generated list query with smart retry and error parsing.
5
- * Generated by Blacksmith. You own this file — customize as needed.
6
- */
7
-
8
- import { useApiQuery } from '@/shared/hooks/use-api-query'
9
- import {
10
- {{snakes}}ListOptions,
11
- } from '@/api/generated/@tanstack/react-query.gen'
12
-
13
- interface Use{{Names}}Params {
14
- page?: number
15
- search?: string
16
- ordering?: string
17
- }
18
-
19
- export function use{{Names}}(params: Use{{Names}}Params = {}) {
20
- return useApiQuery({
21
- ...{{snakes}}ListOptions({
22
- query: {
23
- page: params.page ?? 1,
24
- search: params.search,
25
- ordering: params.ordering ?? '-created_at',
26
- },
27
- }),
28
- select: (data: any) => ({
29
- {{names}}: data.results ?? [],
30
- total: data.count ?? 0,
31
- hasNext: !!data.next,
32
- hasPrev: !!data.previous,
33
- }),
34
- })
35
- }