ruler-components 0.1.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.
Files changed (114) hide show
  1. package/AGENTS.md +9 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +21 -0
  4. package/README.md +45 -0
  5. package/app/docs/[slug]/page.tsx +147 -0
  6. package/app/docs/layout.tsx +26 -0
  7. package/app/docs/page.tsx +148 -0
  8. package/app/favicon.ico +0 -0
  9. package/app/globals.css +168 -0
  10. package/app/icon.png +0 -0
  11. package/app/layout.tsx +90 -0
  12. package/app/opengraph-image.tsx +10 -0
  13. package/app/page.tsx +34 -0
  14. package/app/twitter-image.tsx +10 -0
  15. package/components/docs/accordion-doc-page.tsx +352 -0
  16. package/components/docs/alert-doc-page.tsx +293 -0
  17. package/components/docs/allinput-doc-page.tsx +183 -0
  18. package/components/docs/avatar-doc-page.tsx +424 -0
  19. package/components/docs/badge-doc-page.tsx +363 -0
  20. package/components/docs/button-doc-page.tsx +406 -0
  21. package/components/docs/card-doc-page.tsx +364 -0
  22. package/components/docs/checkbox-doc-page.tsx +277 -0
  23. package/components/docs/colors-doc-page.tsx +430 -0
  24. package/components/docs/dialog-doc-page.tsx +364 -0
  25. package/components/docs/docs-footer.tsx +11 -0
  26. package/components/docs/docs-mobile-menu-bar.tsx +22 -0
  27. package/components/docs/docs-mobile-nav-context.tsx +27 -0
  28. package/components/docs/docs-page.tsx +263 -0
  29. package/components/docs/docs-search.tsx +303 -0
  30. package/components/docs/docs-sidebar.tsx +165 -0
  31. package/components/docs/docs-topbar.tsx +32 -0
  32. package/components/docs/dropdown-doc-page.tsx +522 -0
  33. package/components/docs/getting-started-doc-page.tsx +205 -0
  34. package/components/docs/label-doc-page.tsx +173 -0
  35. package/components/docs/loaders-doc-page.tsx +244 -0
  36. package/components/docs/menu-doc-page.tsx +373 -0
  37. package/components/docs/modal-doc-page.tsx +436 -0
  38. package/components/docs/next-steps.tsx +53 -0
  39. package/components/docs/pagination-doc-page.tsx +316 -0
  40. package/components/docs/progress-doc-page.tsx +387 -0
  41. package/components/docs/radio-doc-page.tsx +270 -0
  42. package/components/docs/skeleton-doc-page.tsx +230 -0
  43. package/components/docs/stepper-doc-page.tsx +309 -0
  44. package/components/docs/switch-doc-page.tsx +264 -0
  45. package/components/docs/table-doc-page.tsx +689 -0
  46. package/components/docs/tabs-doc-page.tsx +359 -0
  47. package/components/docs/theming-doc-page.tsx +243 -0
  48. package/components/docs/tooltip-doc-page.tsx +357 -0
  49. package/components/docs/usage-section.tsx +21 -0
  50. package/components/icons/discord.tsx +9 -0
  51. package/components/icons/github.tsx +9 -0
  52. package/components/icons/x.tsx +9 -0
  53. package/components/installation-section.tsx +34 -0
  54. package/components/landing/feature-highlights.tsx +105 -0
  55. package/components/landing/footer-strip.tsx +45 -0
  56. package/components/landing/hero-card.tsx +14 -0
  57. package/components/landing/hero-spotlight.tsx +126 -0
  58. package/components/landing/hero.tsx +64 -0
  59. package/components/landing/navbar.tsx +44 -0
  60. package/components/landing/quick-start-section.tsx +59 -0
  61. package/components/landing/site-footer.tsx +55 -0
  62. package/components/theme-provider.tsx +60 -0
  63. package/components/ui/accordion.tsx +174 -0
  64. package/components/ui/alert.tsx +103 -0
  65. package/components/ui/allinput.tsx +210 -0
  66. package/components/ui/avatar.tsx +179 -0
  67. package/components/ui/badge.tsx +52 -0
  68. package/components/ui/button.tsx +75 -0
  69. package/components/ui/card.tsx +105 -0
  70. package/components/ui/checkbox.tsx +130 -0
  71. package/components/ui/code-block.tsx +60 -0
  72. package/components/ui/data-table.tsx +235 -0
  73. package/components/ui/dialog.tsx +173 -0
  74. package/components/ui/dropdown.tsx +78 -0
  75. package/components/ui/feature-card.tsx +38 -0
  76. package/components/ui/input.tsx +44 -0
  77. package/components/ui/label.tsx +110 -0
  78. package/components/ui/loaders.tsx +139 -0
  79. package/components/ui/menu.tsx +118 -0
  80. package/components/ui/modal.tsx +399 -0
  81. package/components/ui/package-manager-tabs.tsx +40 -0
  82. package/components/ui/pagination.tsx +200 -0
  83. package/components/ui/progress.tsx +134 -0
  84. package/components/ui/radio.tsx +262 -0
  85. package/components/ui/skeleton.tsx +102 -0
  86. package/components/ui/steppers.tsx +309 -0
  87. package/components/ui/switch.tsx +153 -0
  88. package/components/ui/table.tsx +58 -0
  89. package/components/ui/tabs.tsx +166 -0
  90. package/components/ui/theme-toggle.tsx +60 -0
  91. package/components/ui/tooltip.tsx +238 -0
  92. package/data/color-palette.ts +35 -0
  93. package/data/docs-nav.ts +84 -0
  94. package/eslint.config.mjs +18 -0
  95. package/index.ts +8 -0
  96. package/lib/cn.ts +4 -0
  97. package/lib/color.ts +85 -0
  98. package/lib/og-image.tsx +138 -0
  99. package/lib/theme.ts +33 -0
  100. package/next.config.ts +7 -0
  101. package/package.json +30 -0
  102. package/postcss.config.mjs +7 -0
  103. package/public/dark.png +0 -0
  104. package/public/dark1.png +0 -0
  105. package/public/dark2.png +0 -0
  106. package/public/file.svg +1 -0
  107. package/public/globe.svg +1 -0
  108. package/public/light.png +0 -0
  109. package/public/light1.png +0 -0
  110. package/public/next.svg +1 -0
  111. package/public/vercel.svg +1 -0
  112. package/public/video/hero-demo.mp4 +0 -0
  113. package/public/window.svg +1 -0
  114. package/tsconfig.json +34 -0
@@ -0,0 +1,373 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import {
5
+ Check,
6
+ Copy,
7
+ Download,
8
+ FileText,
9
+ Folder,
10
+ LayoutDashboard,
11
+ LogOut,
12
+ Menu as MenuIcon,
13
+ Pencil,
14
+ Plus,
15
+ Settings,
16
+ Share2,
17
+ Star,
18
+ Trash2,
19
+ User,
20
+ Users,
21
+ } from "lucide-react";
22
+ import { Menu, MenuItem, MenuLabel, MenuDivider, type MenuProps } from "@/components/ui/menu";
23
+ import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card";
24
+ import { Badge } from "@/components/ui/badge";
25
+ import { Tooltip } from "@/components/ui/tooltip";
26
+ import {
27
+ DocsAccessibility,
28
+ DocsApiSection,
29
+ DocsApiTable,
30
+ DocsPage,
31
+ DocsPageHeader,
32
+ DocsSection,
33
+ DocsSectionGrid,
34
+ } from "@/components/docs/docs-page";
35
+ import { cn } from "@/lib/cn";
36
+
37
+ const MENU_API_ROWS = [
38
+ { prop: "variant", type: '"default" | "ghost"', default: '"default"', description: "Bordered surface or a transparent list" },
39
+ { prop: "children", type: "ReactNode", default: "—", description: "MenuItem, MenuLabel, and MenuDivider elements" },
40
+ { prop: "className", type: "string", default: "—", description: "Additional CSS classes" },
41
+ ];
42
+
43
+ const ITEM_API_ROWS = [
44
+ { prop: "label", type: "string", default: "—", description: "Row text" },
45
+ { prop: "icon", type: "LucideIcon", default: "—", description: "Optional leading icon" },
46
+ { prop: "shortcut", type: "string", default: "—", description: "Trailing keyboard shortcut hint, e.g. \"⌘K\"" },
47
+ { prop: "selected", type: "boolean", default: "false", description: "Shows a trailing check mark" },
48
+ { prop: "disabled", type: "boolean", default: "false", description: "Disables the item" },
49
+ { prop: "onClick", type: "() => void", default: "—", description: "Called when the item is chosen" },
50
+ { prop: "variant", type: '"default" | "destructive"', default: '"default"', description: "Red styling for irreversible actions like delete" },
51
+ ];
52
+
53
+ const ACCESSIBILITY_ITEMS = [
54
+ "Menu carries role=\"menu\" and each MenuItem is a real <button> with role=\"menuitem\" — reachable and activatable via keyboard by default.",
55
+ "MenuDivider carries role=\"separator\" — it's structural, not another option.",
56
+ "Disabled items use the native disabled attribute, so they're skipped by screen readers and keyboard focus.",
57
+ "Pair the destructive item variant with an explicit label, like \"Delete\" rather than a bare icon.",
58
+ "Unlike Dropdown, Menu has no built-in open/close behavior — wire up your own trigger (a click, a right-click, a route) and unmount the Menu when it should close.",
59
+ ];
60
+
61
+ type Variant = NonNullable<MenuProps["variant"]>;
62
+
63
+ const VARIANTS: { value: Variant; label: string }[] = [
64
+ { value: "default", label: "Default" },
65
+ { value: "ghost", label: "Ghost" },
66
+ ];
67
+
68
+ function codeFor(variant: Variant, withIcons: boolean, withShortcuts: boolean, withDestructive: boolean) {
69
+ const props = variant !== "default" ? ` variant="${variant}"` : "";
70
+ const icon = (name: string) => (withIcons ? ` icon={${name}}` : "");
71
+ const shortcut = (key: string) => (withShortcuts ? ` shortcut="${key}"` : "");
72
+ const items = [
73
+ `<MenuItem label="Rename"${icon("Pencil")}${shortcut("⌘R")} />`,
74
+ `<MenuItem label="Duplicate"${icon("Copy")}${shortcut("⌘D")} />`,
75
+ `<MenuItem label="Share"${icon("Share2")} />`,
76
+ ];
77
+ if (withDestructive) {
78
+ items.push("<MenuDivider />");
79
+ items.push(`<MenuItem label="Delete"${icon("Trash2")} variant="destructive" />`);
80
+ }
81
+ const body = items.join("\n ");
82
+ return `<Menu${props}>\n ${body}\n</Menu>`;
83
+ }
84
+
85
+ export function MenuDocPage() {
86
+ const [variant, setVariant] = useState<Variant>("default");
87
+ const [withIcons, setWithIcons] = useState(true);
88
+ const [withShortcuts, setWithShortcuts] = useState(true);
89
+ const [withDestructive, setWithDestructive] = useState(true);
90
+ const [copied, setCopied] = useState(false);
91
+
92
+ const [view, setView] = useState<"grid" | "list">("grid");
93
+ const [favorited, setFavorited] = useState(true);
94
+
95
+ const snippet = codeFor(variant, withIcons, withShortcuts, withDestructive);
96
+
97
+ function copySnippet() {
98
+ navigator.clipboard.writeText(snippet).catch(() => {});
99
+ setCopied(true);
100
+ setTimeout(() => setCopied(false), 1200);
101
+ }
102
+
103
+ return (
104
+ <DocsPage>
105
+ <DocsPageHeader
106
+ icon={MenuIcon}
107
+ title="Menu"
108
+ description="A standalone list of actions — the visual surface behind a context menu, command palette, or sidebar, rendered inline rather than anchored to a trigger."
109
+ />
110
+
111
+ <DocsSection
112
+ first
113
+ title="Playground"
114
+ description="Build a menu and copy the exact markup — icons, shortcuts, and a destructive action, live."
115
+ >
116
+ <div className="overflow-hidden rounded-2xl border border-zinc-200 shadow-[0_2px_8px_rgba(0,0,0,0.04)] dark:border-zinc-800 dark:shadow-[0_2px_8px_rgba(0,0,0,0.2)]">
117
+ <div className="relative flex min-h-[16rem] items-center justify-center overflow-hidden bg-zinc-50 p-6 dark:bg-zinc-900/40">
118
+ <div
119
+ aria-hidden
120
+ className="pointer-events-none absolute inset-0 opacity-[0.4] dark:opacity-[0.15]"
121
+ style={{
122
+ backgroundImage:
123
+ "linear-gradient(to right, rgb(161 161 170 / 0.35) 1px, transparent 1px), linear-gradient(to bottom, rgb(161 161 170 / 0.35) 1px, transparent 1px)",
124
+ backgroundSize: "24px 24px",
125
+ }}
126
+ />
127
+ <div
128
+ key={`${variant}-${withIcons}-${withShortcuts}-${withDestructive}`}
129
+ className="relative animate-[pagination-pop_0.2s_ease-out]"
130
+ >
131
+ <Menu variant={variant}>
132
+ <MenuItem
133
+ label="Rename"
134
+ icon={withIcons ? Pencil : undefined}
135
+ shortcut={withShortcuts ? "⌘R" : undefined}
136
+ />
137
+ <MenuItem
138
+ label="Duplicate"
139
+ icon={withIcons ? Copy : undefined}
140
+ shortcut={withShortcuts ? "⌘D" : undefined}
141
+ />
142
+ <MenuItem label="Share" icon={withIcons ? Share2 : undefined} />
143
+ {withDestructive && (
144
+ <>
145
+ <MenuDivider />
146
+ <MenuItem
147
+ label="Delete"
148
+ icon={withIcons ? Trash2 : undefined}
149
+ variant="destructive"
150
+ />
151
+ </>
152
+ )}
153
+ </Menu>
154
+ </div>
155
+ </div>
156
+
157
+ <div className="flex flex-col gap-5 border-t border-zinc-200 p-5 dark:border-zinc-800">
158
+ <div className="flex flex-wrap items-start justify-between gap-6">
159
+ <div>
160
+ <p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
161
+ Variant
162
+ </p>
163
+ <div className="flex flex-wrap items-center gap-1 rounded-lg border border-zinc-200 bg-zinc-50 p-1 dark:border-zinc-800 dark:bg-zinc-900/60">
164
+ {VARIANTS.map((v) => (
165
+ <button
166
+ key={v.value}
167
+ type="button"
168
+ onClick={() => setVariant(v.value)}
169
+ className={cn(
170
+ "rounded-md px-3 py-1.5 text-xs font-medium uppercase tracking-wide transition-colors",
171
+ variant === v.value
172
+ ? "bg-white text-zinc-900 shadow-sm dark:bg-zinc-800 dark:text-white"
173
+ : "text-zinc-500 hover:text-zinc-800 dark:text-zinc-400 dark:hover:text-zinc-200"
174
+ )}
175
+ >
176
+ {v.label}
177
+ </button>
178
+ ))}
179
+ </div>
180
+ </div>
181
+
182
+ <div>
183
+ <p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
184
+ Icons
185
+ </p>
186
+ <button
187
+ type="button"
188
+ onClick={() => setWithIcons((v) => !v)}
189
+ className={cn(
190
+ "flex h-[2.125rem] items-center gap-2 rounded-lg border px-3 text-xs font-medium transition-colors",
191
+ withIcons
192
+ ? "border-zinc-900 bg-zinc-900 text-white dark:border-white dark:bg-white dark:text-zinc-900"
193
+ : "border-zinc-200 text-zinc-500 hover:border-zinc-300 dark:border-zinc-700 dark:text-zinc-400"
194
+ )}
195
+ >
196
+ {withIcons ? "On" : "Off"}
197
+ </button>
198
+ </div>
199
+
200
+ <div>
201
+ <p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
202
+ Shortcuts
203
+ </p>
204
+ <button
205
+ type="button"
206
+ onClick={() => setWithShortcuts((v) => !v)}
207
+ className={cn(
208
+ "flex h-[2.125rem] items-center gap-2 rounded-lg border px-3 text-xs font-medium transition-colors",
209
+ withShortcuts
210
+ ? "border-zinc-900 bg-zinc-900 text-white dark:border-white dark:bg-white dark:text-zinc-900"
211
+ : "border-zinc-200 text-zinc-500 hover:border-zinc-300 dark:border-zinc-700 dark:text-zinc-400"
212
+ )}
213
+ >
214
+ {withShortcuts ? "On" : "Off"}
215
+ </button>
216
+ </div>
217
+
218
+ <div>
219
+ <p className="mb-2 text-xs font-medium uppercase tracking-wide text-zinc-400 dark:text-zinc-500">
220
+ Destructive item
221
+ </p>
222
+ <button
223
+ type="button"
224
+ onClick={() => setWithDestructive((v) => !v)}
225
+ className={cn(
226
+ "flex h-[2.125rem] items-center gap-2 rounded-lg border px-3 text-xs font-medium transition-colors",
227
+ withDestructive
228
+ ? "border-zinc-900 bg-zinc-900 text-white dark:border-white dark:bg-white dark:text-zinc-900"
229
+ : "border-zinc-200 text-zinc-500 hover:border-zinc-300 dark:border-zinc-700 dark:text-zinc-400"
230
+ )}
231
+ >
232
+ {withDestructive ? "On" : "Off"}
233
+ </button>
234
+ </div>
235
+ </div>
236
+
237
+ <div className="flex items-center justify-between gap-3 rounded-xl bg-zinc-900 px-4 py-3 dark:bg-black">
238
+ <pre className="overflow-x-auto font-mono text-[13px] leading-relaxed text-zinc-100">
239
+ <code>{snippet}</code>
240
+ </pre>
241
+ <Tooltip content={copied ? "Copied!" : "Copy code"}>
242
+ <button
243
+ type="button"
244
+ onClick={copySnippet}
245
+ className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-zinc-400 transition-colors hover:bg-white/10 hover:text-white"
246
+ >
247
+ {copied ? <Check className="h-4 w-4 text-emerald-400" /> : <Copy className="h-4 w-4" />}
248
+ </button>
249
+ </Tooltip>
250
+ </div>
251
+ </div>
252
+ </div>
253
+ </DocsSection>
254
+
255
+ <DocsSection
256
+ title="Menu vs. Dropdown"
257
+ description="Menu is the list itself — Dropdown wraps it with a trigger, positioning, and open/close behavior."
258
+ >
259
+ <div className="grid gap-3 sm:grid-cols-2">
260
+ <div className="rounded-xl border border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-950">
261
+ <p className="text-sm font-semibold text-zinc-900 dark:text-white">Use Menu when</p>
262
+ <p className="mt-1.5 text-xs leading-relaxed text-zinc-500 dark:text-zinc-400">
263
+ The list is always visible — a sidebar, a right-click context menu you position yourself, or the
264
+ options pane inside a command palette.
265
+ </p>
266
+ </div>
267
+ <div className="rounded-xl border border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-950">
268
+ <p className="text-sm font-semibold text-zinc-900 dark:text-white">Use Dropdown when</p>
269
+ <p className="mt-1.5 text-xs leading-relaxed text-zinc-500 dark:text-zinc-400">
270
+ You need a button that opens/closes a floating panel — an account menu, a select, a filter. Dropdown
271
+ is built on the same item styling as Menu.
272
+ </p>
273
+ </div>
274
+ </div>
275
+ </DocsSection>
276
+
277
+ <DocsSection title="In context" description="Menu rarely stands alone — here's how it reads inside real UI.">
278
+ <DocsSectionGrid className="lg:grid-cols-[1fr_1.1fr]">
279
+ <Card>
280
+ <CardHeader>
281
+ <div className="flex items-center justify-between gap-3">
282
+ <div>
283
+ <CardTitle>Right-click menu</CardTitle>
284
+ <CardDescription>Positioned by the caller at the click coordinates.</CardDescription>
285
+ </div>
286
+ <Badge variant="outline">Context menu</Badge>
287
+ </div>
288
+ </CardHeader>
289
+ <CardContent>
290
+ <div className="flex flex-col gap-3">
291
+ <div
292
+ className="flex h-24 items-center justify-center rounded-lg border border-dashed border-zinc-300 text-xs text-zinc-400 dark:border-zinc-700 dark:text-zinc-600"
293
+ onContextMenu={(e) => e.preventDefault()}
294
+ >
295
+ Right-click target (menu shown below for reference)
296
+ </div>
297
+ <Menu className="w-48">
298
+ <MenuItem label="Cut" shortcut="⌘X" />
299
+ <MenuItem label="Copy" shortcut="⌘C" />
300
+ <MenuItem label="Paste" shortcut="⌘V" />
301
+ <MenuDivider />
302
+ <MenuItem label="Inspect" icon={FileText} />
303
+ </Menu>
304
+ </div>
305
+ </CardContent>
306
+ </Card>
307
+
308
+ <Card>
309
+ <CardHeader>
310
+ <div className="flex items-center gap-3">
311
+ <div className="flex h-10 w-10 items-center justify-center rounded-xl bg-zinc-100 dark:bg-zinc-800">
312
+ <LayoutDashboard className="h-5 w-5 text-zinc-600 dark:text-zinc-300" />
313
+ </div>
314
+ <div>
315
+ <CardTitle>Sidebar navigation</CardTitle>
316
+ <CardDescription>Grouped, always-visible — no open/close state needed.</CardDescription>
317
+ </div>
318
+ </div>
319
+ </CardHeader>
320
+ <CardContent>
321
+ <Menu variant="ghost" className="w-full">
322
+ <MenuLabel>Workspace</MenuLabel>
323
+ <MenuItem label="Dashboard" icon={LayoutDashboard} selected />
324
+ <MenuItem label="Projects" icon={Folder} />
325
+ <MenuItem label="Team" icon={Users} />
326
+ <MenuDivider />
327
+ <MenuLabel>Account</MenuLabel>
328
+ <MenuItem label="Profile" icon={User} />
329
+ <MenuItem label="Settings" icon={Settings} />
330
+ <MenuItem label="Log out" icon={LogOut} variant="destructive" />
331
+ </Menu>
332
+ </CardContent>
333
+ </Card>
334
+ </DocsSectionGrid>
335
+ </DocsSection>
336
+
337
+ <DocsSection
338
+ title="Command palette"
339
+ description="Grouped, keyboard-first actions — the pattern behind ⌘K launchers."
340
+ >
341
+ <Card className="max-w-lg">
342
+ <CardContent className="pt-6">
343
+ <div className="mb-1 flex items-center gap-2 rounded-lg border border-zinc-200 bg-zinc-50 px-3 py-2 dark:border-zinc-800 dark:bg-zinc-900">
344
+ <span className="text-sm text-zinc-400">Type a command or search...</span>
345
+ </div>
346
+ <Menu variant="ghost" className="w-full">
347
+ <MenuLabel>Suggestions</MenuLabel>
348
+ <MenuItem label="New file" icon={Plus} shortcut="⌘N" />
349
+ <MenuItem label="Export as PDF" icon={Download} shortcut="⌘E" />
350
+ <MenuDivider />
351
+ <MenuLabel>Actions</MenuLabel>
352
+ <MenuItem
353
+ label={favorited ? "Remove from favorites" : "Add to favorites"}
354
+ icon={Star}
355
+ onClick={() => setFavorited((v) => !v)}
356
+ />
357
+ <MenuItem
358
+ label={`View as ${view === "grid" ? "list" : "grid"}`}
359
+ onClick={() => setView((v) => (v === "grid" ? "list" : "grid"))}
360
+ />
361
+ </Menu>
362
+ </CardContent>
363
+ </Card>
364
+ </DocsSection>
365
+
366
+ <DocsApiSection>
367
+ <DocsApiTable title="API Reference — Menu" rows={MENU_API_ROWS} />
368
+ <DocsApiTable title="API Reference — MenuItem" rows={ITEM_API_ROWS} />
369
+ <DocsAccessibility items={ACCESSIBILITY_ITEMS} />
370
+ </DocsApiSection>
371
+ </DocsPage>
372
+ );
373
+ }