Skip to content

Commit 2534519

Browse files
committed
chore: refactor code to separate client and server
1 parent bf5eef4 commit 2534519

23 files changed

+247
-147
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"dependencies": {
1313
"@fontsource-variable/inter": "^5.2.5",
1414
"@fontsource/dm-mono": "^5.2.5",
15+
"@hono/valibot-validator": "^0.5.2",
1516
"@microlink/react-json-view": "^1.26.2",
1617
"@radix-ui/react-dialog": "^1.1.14",
1718
"@radix-ui/react-dropdown-menu": "^2.1.15",
@@ -26,6 +27,7 @@
2627
"hono": "^4.7.11",
2728
"lucide-react": "^0.511.0",
2829
"motion": "^12.15.0",
30+
"nanoid": "^5.1.5",
2931
"prismjs": "^1.30.0",
3032
"react": "^19.1.0",
3133
"react-dom": "^19.1.0",

pnpm-lock.yaml

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.tsx renamed to src/client/App.tsx

Lines changed: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,35 @@
1-
import { Editor } from "@/Editor";
2-
import { Preview } from "@/Preview";
3-
import { Logo } from "@/components/Logo";
4-
import { ResizableHandle, ResizablePanelGroup } from "@/components/Resizable";
5-
import { useStore } from "@/store";
1+
import { Editor } from "@/client/Editor";
2+
import { Preview } from "@/client/Preview";
3+
import { Logo } from "@/client/components/Logo";
4+
import {
5+
ResizableHandle,
6+
ResizablePanelGroup,
7+
} from "@/client/components/Resizable";
8+
import { useStore } from "@/client/store";
69
import {
710
DropdownMenu,
811
DropdownMenuContent,
912
DropdownMenuItem,
1013
DropdownMenuPortal,
1114
DropdownMenuTrigger,
12-
} from "@/components/DropdownMenu";
13-
import { type FC, useEffect, useMemo } from "react";
14-
15-
import { useTheme } from "@/contexts/theme";
15+
} from "@/client/components/DropdownMenu";
16+
import {
17+
type FC,
18+
useCallback,
19+
useEffect,
20+
useMemo,
21+
useRef,
22+
useState,
23+
} from "react";
24+
import { useTheme } from "@/client/contexts/theme";
1625
import { MoonIcon, SunIcon, SunMoonIcon } from "lucide-react";
17-
import { Button } from "./components/Button";
26+
import { Button } from "@/client/components/Button";
27+
import {
28+
Tooltip,
29+
TooltipContent,
30+
TooltipTrigger,
31+
} from "@/client/components/Tooltip";
32+
import { rpc } from "@/utils/rpc";
1833

1934
type GoPreviewDef = (v: unknown) => Promise<string>;
2035

@@ -73,11 +88,15 @@ export const App = () => {
7388
<main className="flex h-dvh w-screen flex-col items-center bg-surface-primary">
7489
{/* NAV BAR */}
7590
<nav className="flex h-16 w-full justify-between border-b border-b-surface-quaternary px-6 py-2">
76-
<div className="flex items-center gap-2">
77-
<Logo className="text-content-primary" height={24} />
78-
<p className="font-semibold text-content-primary text-xl">
79-
Playground
80-
</p>
91+
<div className="flex items-center justify-center gap-4">
92+
<div className="flex items-center gap-2">
93+
<Logo className="text-content-primary" height={24} />
94+
<p className="font-semibold text-content-primary text-xl">
95+
Playground
96+
</p>
97+
</div>
98+
99+
<ShareButton />
81100
</div>
82101

83102
<div className="flex items-center gap-3">
@@ -160,3 +179,51 @@ const ThemeSelector: FC = () => {
160179
</DropdownMenu>
161180
);
162181
};
182+
183+
const ShareButton: FC = () => {
184+
const $code = useStore((state) => state.code);
185+
const [isCopied, setIsCopied] = useState(() => false);
186+
const timeoutId = useRef<ReturnType<typeof setTimeout>>(undefined);
187+
188+
const onShare = useCallback(async () => {
189+
try {
190+
const { id } = await rpc.parameters
191+
.$post({ json: { code: $code } })
192+
.then((res) => res.json());
193+
194+
const { protocol, host } = window.location;
195+
window.navigator.clipboard.writeText(
196+
`${protocol}//${host}/parameters/${id}`,
197+
);
198+
199+
setIsCopied(() => true);
200+
} catch (e) {
201+
console.error(e);
202+
}
203+
}, [$code]);
204+
205+
useEffect(() => {
206+
if (!isCopied) {
207+
return;
208+
}
209+
210+
clearTimeout(timeoutId.current);
211+
const id = setTimeout(() => {
212+
setIsCopied(() => false);
213+
}, 1000);
214+
timeoutId.current = id;
215+
216+
return () => clearTimeout(timeoutId.current);
217+
}, [isCopied]);
218+
219+
return (
220+
<Tooltip open={isCopied}>
221+
<TooltipTrigger asChild={true}>
222+
<Button size="sm" onClick={onShare}>
223+
Share
224+
</Button>
225+
</TooltipTrigger>
226+
<TooltipContent>Copied to clipboard</TooltipContent>
227+
</Tooltip>
228+
);
229+
};

src/Editor.tsx renamed to src/client/Editor.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import { Button } from "@/components/Button";
1+
import { Button } from "@/client/components/Button";
22
import {
33
DropdownMenu,
44
DropdownMenuContent,
55
DropdownMenuItem,
66
DropdownMenuPortal,
77
DropdownMenuTrigger,
8-
} from "@/components/DropdownMenu";
9-
import { ResizablePanel } from "@/components/Resizable";
10-
import * as Tabs from "@/components/Tabs";
11-
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/Tooltip";
12-
import { useStore } from "@/store";
8+
} from "@/client/components/DropdownMenu";
9+
import { ResizablePanel } from "@/client/components/Resizable";
10+
import * as Tabs from "@/client/components/Tabs";
11+
import { Tooltip, TooltipContent, TooltipTrigger } from "@/client/components/Tooltip";
12+
import { useStore } from "@/client/store";
1313
import {
1414
BookIcon,
1515
CheckIcon,

src/Preview.tsx renamed to src/client/Preview.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
import { Button } from "@/components/Button";
1+
import { Button } from "@/client/components/Button";
22
import {
33
ResizableHandle,
44
ResizablePanel,
55
ResizablePanelGroup,
6-
} from "@/components/Resizable";
7-
import * as Tabs from "@/components/Tabs";
6+
} from "@/client/components/Resizable";
7+
import * as Tabs from "@/client/components/Tabs";
88
import {
99
type Diagnostic,
1010
type InternalDiagnostic,
1111
outputToDiagnostics,
12-
} from "@/diagnostics";
12+
} from "@/client/diagnostics";
1313
import type { ParserLog, PreviewOutput } from "@/gen/types";
14-
import { useDebouncedValue } from "@/hooks/debounce";
15-
import { useStore } from "@/store";
14+
import { useDebouncedValue } from "@/client/hooks/debounce";
15+
import { useStore } from "@/client/store";
1616
import { cn } from "@/utils/cn";
1717
import * as Dialog from "@radix-ui/react-dialog";
1818
import {
@@ -29,7 +29,7 @@ import { AnimatePresence, motion } from "motion/react";
2929
import { type FC, useCallback, useEffect, useMemo, useState } from "react";
3030
import { useSearchParams } from "react-router";
3131
import ReactJsonView from "@microlink/react-json-view";
32-
import { useTheme } from "@/contexts/theme";
32+
import { useTheme } from "@/client/contexts/theme";
3333

3434
export const Preview: FC = () => {
3535
const $wasmState = useStore((state) => state.wasmState);

src/components/Button.tsx renamed to src/client/components/Button.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import { Slot } from "@radix-ui/react-slot";
66
import { type VariantProps, cva } from "class-variance-authority";
77
import { forwardRef } from "react";
8-
import { cn } from "../utils/cn";
8+
import { cn } from "@/utils/cn";
99

1010
export const buttonVariants = cva(
1111
`inline-flex items-center justify-center gap-1 whitespace-nowrap
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

src/diagnostics.ts renamed to src/client/diagnostics.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type {
33
Parameter,
44
ParserLog,
55
PreviewOutput,
6-
} from "./gen/types";
6+
} from "@/gen/types";
77

88
type FriendlyDiagnosticWithoutKind = Omit<FriendlyDiagnostic, "extra">;
99

File renamed without changes.
File renamed without changes.

src/main.tsx renamed to src/client/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { TooltipProvider } from "@/components/Tooltip";
2-
import { ThemeProvider } from "@/contexts/theme.tsx";
1+
import { TooltipProvider } from "@/client/components/Tooltip";
2+
import { ThemeProvider } from "@/client/contexts/theme.tsx";
33
import { StrictMode } from "react";
44
import { createRoot } from "react-dom/client";
55
import { BrowserRouter } from "react-router";
66
import { App } from "./App.tsx";
7-
import "./index.css";
7+
import "@/client/index.css";
88

99
const root = document.getElementById("root");
1010

src/store.tsx renamed to src/client/store.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { create } from "zustand";
2-
import type { Diagnostic } from "@/diagnostics";
2+
import type { Diagnostic } from "@/client/diagnostics";
33

44
const defaultCode = `terraform {
55
required_providers {

0 commit comments

Comments
 (0)