create-swift-rust 0.3.1 → 0.7.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/index.js +87 -881
- package/dist/index.js.map +1 -1
- package/package.json +8 -6
- package/templates/default/README.md +29 -0
- package/templates/default/_env.example +5 -0
- package/templates/default/_env.local +5 -0
- package/templates/default/_gitignore +14 -0
- package/templates/default/biome.json +12 -0
- package/templates/default/globals.d.ts +19 -0
- package/templates/default/package.json +30 -0
- package/templates/default/postcss.config.mjs +7 -0
- package/templates/default/public/blog/introducing-swift-rust.svg +12 -0
- package/templates/default/public/og-image.svg +25 -0
- package/templates/default/public/samples/axelborg-towers-modern-architecture.jpg +0 -0
- package/templates/default/public/samples/brown-high-skyscrapers.jpg +0 -0
- package/templates/default/public/samples/close-up-portrait-gorgeous-young-woman.jpg +0 -0
- package/templates/default/public/samples/full-shot-woman-taking-selfie.jpg +0 -0
- package/templates/default/public/samples/happy-black-parents-with-kids-making-video-call-smart-phone-home.jpg +0 -0
- package/templates/default/public/samples/metaverse-concept-collage-design.jpg +0 -0
- package/templates/default/src/app/about/layout.tsx +5 -0
- package/templates/default/src/app/about/page.tsx +74 -0
- package/templates/default/src/app/about/team/page.tsx +88 -0
- package/templates/default/src/app/api/contact/route.ts +15 -0
- package/templates/default/src/app/api/health/route.ts +7 -0
- package/templates/default/src/app/api/posts/[id]/route.ts +33 -0
- package/templates/default/src/app/api/posts/route.ts +29 -0
- package/templates/default/src/app/api/search/route.ts +15 -0
- package/templates/default/src/app/api/stats/route.ts +16 -0
- package/templates/default/src/app/blog/[slug]/page.tsx +116 -0
- package/templates/default/src/app/blog/page.tsx +101 -0
- package/templates/default/src/app/blog/tag/[tag]/page.tsx +82 -0
- package/templates/default/src/app/contact/page.tsx +131 -0
- package/templates/default/src/app/dashboard/analytics/page.tsx +103 -0
- package/templates/default/src/app/dashboard/layout.tsx +11 -0
- package/templates/default/src/app/dashboard/loading.tsx +18 -0
- package/templates/default/src/app/dashboard/page.tsx +181 -0
- package/templates/default/src/app/dashboard/posts/[id]/not-found.tsx +23 -0
- package/templates/default/src/app/dashboard/posts/[id]/page.tsx +87 -0
- package/templates/default/src/app/dashboard/posts/new/page.tsx +103 -0
- package/templates/default/src/app/dashboard/posts/page.tsx +81 -0
- package/templates/default/src/app/dashboard/settings/page.tsx +119 -0
- package/templates/default/src/app/error.tsx +42 -0
- package/templates/default/src/app/favicon.ico +0 -0
- package/templates/default/src/app/favicon.svg +8 -0
- package/templates/default/src/app/fonts/page.tsx +610 -0
- package/templates/default/src/app/globals.css +238 -0
- package/templates/default/src/app/images/page.tsx +56 -0
- package/templates/default/src/app/layout.tsx +44 -0
- package/templates/default/src/app/loading.tsx +13 -0
- package/templates/default/src/app/not-found.tsx +25 -0
- package/templates/default/src/app/page.tsx +410 -0
- package/templates/default/src/app/videos/page.tsx +182 -0
- package/templates/default/src/components/font-studio.tsx +378 -0
- package/templates/default/src/components/footer.tsx +75 -0
- package/templates/default/src/components/logo.tsx +26 -0
- package/templates/default/src/components/nav.tsx +102 -0
- package/templates/default/src/components/sidebar.tsx +109 -0
- package/templates/default/src/lib/blur.ts +5 -0
- package/templates/default/src/lib/format.ts +31 -0
- package/templates/default/src/lib/posts.ts +132 -0
- package/templates/default/src/lib/site.config.ts +39 -0
- package/templates/default/src/lib/stats.ts +25 -0
- package/templates/default/swift-rust.config.json +8 -0
- package/templates/default/tsconfig.json +29 -0
- package/templates/default/vercel.json +23 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
@theme {
|
|
4
|
+
--color-bg: #fafaf9;
|
|
5
|
+
--color-surface: #ffffff;
|
|
6
|
+
--color-surface-2: #f5f5f4;
|
|
7
|
+
--color-border: #e7e5e4;
|
|
8
|
+
--color-border-strong: #d6d3d1;
|
|
9
|
+
--color-fg: #0a0a0a;
|
|
10
|
+
--color-fg-muted: #57534e;
|
|
11
|
+
--color-fg-subtle: #78716c;
|
|
12
|
+
--color-accent: #ea580c;
|
|
13
|
+
--color-accent-hover: #c2410c;
|
|
14
|
+
--color-accent-soft: #fff7ed;
|
|
15
|
+
--color-success: #16a34a;
|
|
16
|
+
--color-danger: #dc2626;
|
|
17
|
+
|
|
18
|
+
--font-sans: var(--font-sans), ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
19
|
+
--font-mono: var(--font-mono), ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace;
|
|
20
|
+
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", serif;
|
|
21
|
+
|
|
22
|
+
--radius-sm: 6px;
|
|
23
|
+
--radius-md: 10px;
|
|
24
|
+
--radius-lg: 14px;
|
|
25
|
+
|
|
26
|
+
--shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.04);
|
|
27
|
+
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.06), 0 1px 2px -1px rgb(0 0 0 / 0.04);
|
|
28
|
+
--shadow-md: 0 4px 12px -2px rgb(0 0 0 / 0.06), 0 2px 4px -2px rgb(0 0 0 / 0.04);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@variant dark (&:where(.dark, .dark *));
|
|
32
|
+
|
|
33
|
+
@layer base {
|
|
34
|
+
* {
|
|
35
|
+
border-color: var(--color-border);
|
|
36
|
+
}
|
|
37
|
+
html {
|
|
38
|
+
-webkit-font-smoothing: antialiased;
|
|
39
|
+
-moz-osx-font-smoothing: grayscale;
|
|
40
|
+
text-rendering: optimizeLegibility;
|
|
41
|
+
}
|
|
42
|
+
body {
|
|
43
|
+
background: var(--color-bg);
|
|
44
|
+
color: var(--color-fg);
|
|
45
|
+
font-family: var(--font-sans);
|
|
46
|
+
font-feature-settings: "ss01", "cv11";
|
|
47
|
+
}
|
|
48
|
+
::selection {
|
|
49
|
+
background: var(--color-accent);
|
|
50
|
+
color: white;
|
|
51
|
+
}
|
|
52
|
+
a {
|
|
53
|
+
color: inherit;
|
|
54
|
+
text-decoration: none;
|
|
55
|
+
}
|
|
56
|
+
hr {
|
|
57
|
+
border: 0;
|
|
58
|
+
border-top: 1px solid var(--color-border);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@utility container-page {
|
|
63
|
+
max-width: 72rem;
|
|
64
|
+
margin-left: auto;
|
|
65
|
+
margin-right: auto;
|
|
66
|
+
padding-left: 1.5rem;
|
|
67
|
+
padding-right: 1.5rem;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@utility container-prose {
|
|
71
|
+
max-width: 42rem;
|
|
72
|
+
margin-left: auto;
|
|
73
|
+
margin-right: auto;
|
|
74
|
+
padding-left: 1.5rem;
|
|
75
|
+
padding-right: 1.5rem;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@layer components {
|
|
79
|
+
.btn {
|
|
80
|
+
display: inline-flex;
|
|
81
|
+
align-items: center;
|
|
82
|
+
justify-content: center;
|
|
83
|
+
gap: 0.5rem;
|
|
84
|
+
height: 2.5rem;
|
|
85
|
+
padding: 0 1rem;
|
|
86
|
+
border-radius: var(--radius-md);
|
|
87
|
+
font-size: 0.875rem;
|
|
88
|
+
font-weight: 500;
|
|
89
|
+
transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
|
|
90
|
+
cursor: pointer;
|
|
91
|
+
border: 1px solid transparent;
|
|
92
|
+
white-space: nowrap;
|
|
93
|
+
}
|
|
94
|
+
.btn-primary {
|
|
95
|
+
background: var(--color-fg);
|
|
96
|
+
color: var(--color-bg);
|
|
97
|
+
}
|
|
98
|
+
.btn-primary:hover {
|
|
99
|
+
background: #1c1c1c;
|
|
100
|
+
}
|
|
101
|
+
.btn-accent {
|
|
102
|
+
background: var(--color-accent);
|
|
103
|
+
color: white;
|
|
104
|
+
}
|
|
105
|
+
.btn-accent:hover {
|
|
106
|
+
background: var(--color-accent-hover);
|
|
107
|
+
}
|
|
108
|
+
.btn-outline {
|
|
109
|
+
background: transparent;
|
|
110
|
+
color: var(--color-fg);
|
|
111
|
+
border-color: var(--color-border-strong);
|
|
112
|
+
}
|
|
113
|
+
.btn-outline:hover {
|
|
114
|
+
background: var(--color-surface-2);
|
|
115
|
+
}
|
|
116
|
+
.btn-ghost {
|
|
117
|
+
background: transparent;
|
|
118
|
+
color: var(--color-fg-muted);
|
|
119
|
+
}
|
|
120
|
+
.btn-ghost:hover {
|
|
121
|
+
background: var(--color-surface-2);
|
|
122
|
+
color: var(--color-fg);
|
|
123
|
+
}
|
|
124
|
+
.btn-sm {
|
|
125
|
+
height: 2rem;
|
|
126
|
+
padding: 0 0.75rem;
|
|
127
|
+
font-size: 0.8125rem;
|
|
128
|
+
}
|
|
129
|
+
.btn-lg {
|
|
130
|
+
height: 2.75rem;
|
|
131
|
+
padding: 0 1.25rem;
|
|
132
|
+
font-size: 0.9375rem;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.card {
|
|
136
|
+
background: var(--color-surface);
|
|
137
|
+
border: 1px solid var(--color-border);
|
|
138
|
+
border-radius: var(--radius-lg);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.badge {
|
|
142
|
+
display: inline-flex;
|
|
143
|
+
align-items: center;
|
|
144
|
+
gap: 0.375rem;
|
|
145
|
+
padding: 0.125rem 0.5rem;
|
|
146
|
+
font-size: 0.75rem;
|
|
147
|
+
font-weight: 500;
|
|
148
|
+
border-radius: 999px;
|
|
149
|
+
background: var(--color-surface-2);
|
|
150
|
+
color: var(--color-fg-muted);
|
|
151
|
+
border: 1px solid var(--color-border);
|
|
152
|
+
}
|
|
153
|
+
.badge-accent {
|
|
154
|
+
background: var(--color-accent-soft);
|
|
155
|
+
color: var(--color-accent);
|
|
156
|
+
border-color: transparent;
|
|
157
|
+
}
|
|
158
|
+
.badge-success {
|
|
159
|
+
background: #f0fdf4;
|
|
160
|
+
color: #15803d;
|
|
161
|
+
border-color: transparent;
|
|
162
|
+
}
|
|
163
|
+
.badge-dot::before {
|
|
164
|
+
content: "";
|
|
165
|
+
display: inline-block;
|
|
166
|
+
width: 6px;
|
|
167
|
+
height: 6px;
|
|
168
|
+
border-radius: 999px;
|
|
169
|
+
background: currentColor;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.input {
|
|
173
|
+
display: block;
|
|
174
|
+
width: 100%;
|
|
175
|
+
height: 2.5rem;
|
|
176
|
+
padding: 0 0.75rem;
|
|
177
|
+
border-radius: var(--radius-md);
|
|
178
|
+
background: var(--color-surface);
|
|
179
|
+
border: 1px solid var(--color-border);
|
|
180
|
+
color: var(--color-fg);
|
|
181
|
+
font-size: 0.875rem;
|
|
182
|
+
transition: border-color 120ms ease, box-shadow 120ms ease;
|
|
183
|
+
}
|
|
184
|
+
.input:focus {
|
|
185
|
+
outline: none;
|
|
186
|
+
border-color: var(--color-accent);
|
|
187
|
+
box-shadow: 0 0 0 3px var(--color-accent-soft);
|
|
188
|
+
}
|
|
189
|
+
.textarea {
|
|
190
|
+
display: block;
|
|
191
|
+
width: 100%;
|
|
192
|
+
min-height: 8rem;
|
|
193
|
+
padding: 0.625rem 0.75rem;
|
|
194
|
+
border-radius: var(--radius-md);
|
|
195
|
+
background: var(--color-surface);
|
|
196
|
+
border: 1px solid var(--color-border);
|
|
197
|
+
color: var(--color-fg);
|
|
198
|
+
font-size: 0.875rem;
|
|
199
|
+
font-family: var(--font-sans);
|
|
200
|
+
resize: vertical;
|
|
201
|
+
transition: border-color 120ms ease, box-shadow 120ms ease;
|
|
202
|
+
}
|
|
203
|
+
.textarea:focus {
|
|
204
|
+
outline: none;
|
|
205
|
+
border-color: var(--color-accent);
|
|
206
|
+
box-shadow: 0 0 0 3px var(--color-accent-soft);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.link {
|
|
210
|
+
color: var(--color-accent);
|
|
211
|
+
transition: color 120ms ease;
|
|
212
|
+
}
|
|
213
|
+
.link:hover {
|
|
214
|
+
color: var(--color-accent-hover);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.divider {
|
|
218
|
+
height: 1px;
|
|
219
|
+
background: var(--color-border);
|
|
220
|
+
border: 0;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
@keyframes pulse-dot {
|
|
225
|
+
0%, 100% { opacity: 1; transform: scale(1); }
|
|
226
|
+
50% { opacity: 0.6; transform: scale(0.9); }
|
|
227
|
+
}
|
|
228
|
+
.pulse-dot {
|
|
229
|
+
animation: pulse-dot 2s ease-in-out infinite;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
@keyframes fade-in {
|
|
233
|
+
from { opacity: 0; transform: translateY(4px); }
|
|
234
|
+
to { opacity: 1; transform: translateY(0); }
|
|
235
|
+
}
|
|
236
|
+
.fade-in {
|
|
237
|
+
animation: fade-in 320ms ease-out both;
|
|
238
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Metadata } from "swift-rust";
|
|
2
|
+
import Image from "swift-rust/image";
|
|
3
|
+
import { BLUR } from "@/lib/blur";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = { title: "Images" };
|
|
6
|
+
|
|
7
|
+
const IMAGES = [
|
|
8
|
+
{ src: "/samples/axelborg-towers-modern-architecture.jpg", alt: "Modern architecture towers", w: 3456, h: 2635, label: "4:3" },
|
|
9
|
+
{ src: "/samples/full-shot-woman-taking-selfie.jpg", alt: "Woman taking a selfie", w: 5327, h: 7990, label: "2:3" },
|
|
10
|
+
{ src: "/samples/metaverse-concept-collage-design.jpg", alt: "Metaverse concept collage", w: 6000, h: 4000, label: "3:2" },
|
|
11
|
+
{ src: "/samples/happy-black-parents-with-kids-making-video-call-smart-phone-home.jpg", alt: "Family on a video call at home", w: 6000, h: 4000, label: "3:2" },
|
|
12
|
+
{ src: "/samples/brown-high-skyscrapers.jpg", alt: "Tall brown skyscrapers", w: 4000, h: 5000, label: "4:5" },
|
|
13
|
+
{ src: "/samples/close-up-portrait-gorgeous-young-woman.jpg", alt: "Close-up portrait of a young woman", w: 8494, h: 5663, label: "3:2" },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
export default function ImagesPage() {
|
|
17
|
+
return (
|
|
18
|
+
<div className="container-page py-16 sm:py-20">
|
|
19
|
+
<p className="text-[0.75rem] font-semibold uppercase tracking-wider text-[var(--color-fg-subtle)]">
|
|
20
|
+
Showcase
|
|
21
|
+
</p>
|
|
22
|
+
<h1 className="mt-2 text-4xl font-semibold tracking-tight sm:text-5xl">Images</h1>
|
|
23
|
+
<p className="mt-4 max-w-2xl text-[var(--color-fg-muted)]">
|
|
24
|
+
The Image component handles sizing, format negotiation, and lazy loading. These are local
|
|
25
|
+
sample photos — replace with your own.
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
<div className="mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
|
29
|
+
{IMAGES.map((img) => (
|
|
30
|
+
<figure
|
|
31
|
+
key={img.src}
|
|
32
|
+
className="group overflow-hidden rounded-2xl border border-[var(--color-border)] bg-[var(--color-surface)]"
|
|
33
|
+
>
|
|
34
|
+
<div className="relative aspect-[4/3] overflow-hidden bg-[var(--color-surface-2)]">
|
|
35
|
+
<Image
|
|
36
|
+
src={img.src}
|
|
37
|
+
alt={img.alt}
|
|
38
|
+
width={img.w}
|
|
39
|
+
height={img.h}
|
|
40
|
+
placeholder="blur"
|
|
41
|
+
blurDataURL={BLUR}
|
|
42
|
+
className="h-full w-full object-cover transition-transform duration-500 group-hover:scale-105"
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
<figcaption className="flex items-center justify-between border-t border-[var(--color-border)] px-4 py-3 text-[0.8125rem]">
|
|
46
|
+
<span className="font-mono text-[var(--color-fg-muted)]">
|
|
47
|
+
{img.src.split("/").pop()}
|
|
48
|
+
</span>
|
|
49
|
+
<span className="badge">{img.label}</span>
|
|
50
|
+
</figcaption>
|
|
51
|
+
</figure>
|
|
52
|
+
))}
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import "./globals.css";
|
|
3
|
+
import { Footer } from "@/components/footer";
|
|
4
|
+
import { Nav } from "@/components/nav";
|
|
5
|
+
import { Geist, GeistMono } from "swift-rust/font/google";
|
|
6
|
+
|
|
7
|
+
const geist = Geist({ variable: true, subsets: ["latin"] });
|
|
8
|
+
const geistMono = GeistMono({ variable: true, subsets: ["latin"] });
|
|
9
|
+
|
|
10
|
+
const fontSansClass = geist.className;
|
|
11
|
+
const fontMonoClass = geistMono.className;
|
|
12
|
+
|
|
13
|
+
export const metadata = {
|
|
14
|
+
title: {
|
|
15
|
+
template: "%s | Swift Rust",
|
|
16
|
+
default: "Swift Rust — The React framework powered with Rust + Bun",
|
|
17
|
+
},
|
|
18
|
+
description:
|
|
19
|
+
"Swift Rust is a Next.js-compatible full-stack React framework powered with Rust + Bun. TSX, streaming SSR, four rendering modes, 10x faster than Next.js, single binary deploy.",
|
|
20
|
+
openGraph: {
|
|
21
|
+
title: "Swift Rust",
|
|
22
|
+
description: "The React framework powered with Rust + Bun.",
|
|
23
|
+
type: "website",
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default function RootLayout({ children }: { children: ReactNode }) {
|
|
28
|
+
return (
|
|
29
|
+
<html
|
|
30
|
+
lang="en"
|
|
31
|
+
className={`${geist.variable ?? ""} ${geistMono.variable ?? ""} ${fontSansClass} ${fontMonoClass}`.trim()}
|
|
32
|
+
style={{
|
|
33
|
+
["--font-sans" as string]: "'Geist', system-ui, sans-serif",
|
|
34
|
+
["--font-mono" as string]: "'Geist Mono', ui-monospace, monospace",
|
|
35
|
+
}}
|
|
36
|
+
>
|
|
37
|
+
<body className="min-h-screen bg-[var(--color-bg)] font-sans text-[var(--color-fg)] antialiased">
|
|
38
|
+
<Nav />
|
|
39
|
+
<main className="min-h-[calc(100vh-3.5rem)]">{children}</main>
|
|
40
|
+
<Footer />
|
|
41
|
+
</body>
|
|
42
|
+
</html>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default function GlobalLoading() {
|
|
2
|
+
return (
|
|
3
|
+
<div className="container-page py-20">
|
|
4
|
+
<div className="mx-auto max-w-md space-y-4">
|
|
5
|
+
<div className="h-3 w-24 animate-pulse rounded bg-[var(--color-surface-2)]" />
|
|
6
|
+
<div className="h-9 w-72 animate-pulse rounded bg-[var(--color-surface-2)]" />
|
|
7
|
+
<div className="h-4 w-96 animate-pulse rounded bg-[var(--color-surface-2)]" />
|
|
8
|
+
<div className="h-4 w-80 animate-pulse rounded bg-[var(--color-surface-2)]" />
|
|
9
|
+
<div className="mt-8 h-40 w-full animate-pulse rounded-2xl bg-[var(--color-surface-2)]" />
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Link } from "swift-rust";
|
|
2
|
+
|
|
3
|
+
export default function GlobalNotFound() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="container-page py-24 sm:py-32">
|
|
6
|
+
<div className="mx-auto max-w-xl text-center">
|
|
7
|
+
<p className="font-mono text-[0.875rem] font-medium text-[var(--color-accent)]">404</p>
|
|
8
|
+
<h1 className="mt-3 text-balance text-5xl font-semibold tracking-tight sm:text-6xl">
|
|
9
|
+
Page not found.
|
|
10
|
+
</h1>
|
|
11
|
+
<p className="mt-5 text-pretty text-lg leading-relaxed text-[var(--color-fg-muted)]">
|
|
12
|
+
The page you were looking for has moved, was renamed, or never existed.
|
|
13
|
+
</p>
|
|
14
|
+
<div className="mt-8 flex justify-center gap-2">
|
|
15
|
+
<Link href="/" className="btn btn-primary">
|
|
16
|
+
Back to home
|
|
17
|
+
</Link>
|
|
18
|
+
<Link href="/blog" className="btn btn-outline">
|
|
19
|
+
Read the blog
|
|
20
|
+
</Link>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|