Skip to content

Commit 08ce7ad

Browse files
committed
Standalone preview
1 parent 77fa521 commit 08ce7ad

File tree

3 files changed

+98
-17
lines changed

3 files changed

+98
-17
lines changed

playground/src/app.jsx

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,29 @@ const defaultCss = `.preview-container {
2020
}`;
2121

2222
function App() {
23-
const defaultInput = React.useMemo(() => {
24-
return (
25-
readHash() || {
26-
mdx: defaultCode,
27-
css: defaultCss,
28-
config: {
29-
lineNumbers: false,
30-
showCopyButton: false,
31-
theme: "material-darker",
32-
},
33-
}
34-
);
23+
const data = React.useMemo(() => {
24+
const input = readHash() || {
25+
mdx: defaultCode,
26+
css: defaultCss,
27+
config: {
28+
lineNumbers: false,
29+
showCopyButton: false,
30+
theme: "material-darker",
31+
},
32+
};
33+
const params = new URL(location).searchParams;
34+
const standalonePreview = !!params.get("preview");
35+
return { input, standalonePreview };
3536
}, []);
36-
const [input, setInput] = useState(defaultInput);
37+
const [input, setInput] = useState(data.input);
3738

3839
React.useEffect(() => {
3940
writeHash(input);
4041
}, [input]);
4142

42-
return (
43+
return data.standalonePreview ? (
44+
<Preview input={input} standalone={true} />
45+
) : (
4346
<div className="app">
4447
<header>
4548
<a className="code-hike" href="https://codehike.org">

playground/src/index.css

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,16 @@ main {
136136

137137
.preview {
138138
min-width: 600px;
139-
border-left: 2px solid cadetblue;
140139
flex: 1;
141140
min-height: 0;
142141
overflow: auto;
143142
}
144143

144+
.preview.standalone {
145+
overflow: unset;
146+
padding: 0.1px;
147+
}
148+
145149
.preview-error {
146150
color: #be0924;
147151
padding: 0.5rem 1.5rem;
@@ -172,3 +176,28 @@ main {
172176
opacity: 0.8;
173177
filter: blur(1.5px);
174178
}
179+
180+
.standalone-link {
181+
position: fixed;
182+
top: 3.6rem;
183+
right: 1.6rem;
184+
z-index: 3;
185+
background-color: #222;
186+
color: #fafafa;
187+
border-radius: 4px;
188+
border: 1px solid #fafafa;
189+
}
190+
191+
.standalone .standalone-link {
192+
top: 2rem;
193+
}
194+
195+
.standalone-link:hover {
196+
background-color: #000;
197+
}
198+
.icon {
199+
width: 24px;
200+
height: 24px;
201+
display: block;
202+
padding: 4px;
203+
}

playground/src/preview.jsx

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ import { CH } from "@code-hike/mdx/components";
66
import "@code-hike/mdx/styles.css";
77
import { ErrorBoundary } from "react-error-boundary";
88
import { getTheme } from "./themes";
9+
import { toHash } from "./hash";
910

1011
export function Preview(props) {
1112
return (
12-
<div className="preview">
13+
<div className={`preview ${props.standalone ? "standalone" : ""}`}>
1314
<ErrorBoundary
1415
resetKeys={[props.input.mdx, props.input.css, props.input.config]}
1516
FallbackComponent={ErrorFallback}
@@ -28,7 +29,7 @@ function ErrorFallback({ error }) {
2829
);
2930
}
3031

31-
function InnerPreview({ input }) {
32+
function InnerPreview({ input, standalone }) {
3233
const [Content, setContent] = useState(undefined);
3334
const [error, setError] = useState(undefined);
3435
useEffect(() => {
@@ -67,9 +68,57 @@ function InnerPreview({ input }) {
6768
<pre>{error}</pre>
6869
</div>
6970
) : null}
71+
{standalone ? (
72+
<a href={`/#${toHash(input)}`} className="standalone-link">
73+
<PlaygroundIcon />
74+
</a>
75+
) : (
76+
<a href={`/?preview=1#${toHash(input)}`} className="standalone-link">
77+
<ExternalIcon />
78+
</a>
79+
)}
7080
<div className={`preview-container ${error ? "with-error" : ""}`}>
7181
{Content ? <Content components={{ CH }} /> : null}
7282
</div>
7383
</>
7484
);
7585
}
86+
87+
function ExternalIcon() {
88+
return (
89+
<svg
90+
className="icon"
91+
fill="none"
92+
stroke="currentColor"
93+
viewBox="0 0 24 24"
94+
xmlns="http://www.w3.org/2000/svg"
95+
>
96+
<title>Open in new window</title>
97+
<path
98+
strokeLinecap="round"
99+
strokeLinejoin="round"
100+
strokeWidth={2}
101+
d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
102+
/>
103+
</svg>
104+
);
105+
}
106+
function PlaygroundIcon() {
107+
return (
108+
<svg
109+
className="icon"
110+
fill="none"
111+
stroke="currentColor"
112+
viewBox="0 0 24 24"
113+
xmlns="http://www.w3.org/2000/svg"
114+
>
115+
<title>Open playground</title>
116+
<path
117+
strokeLinecap="round"
118+
strokeLinejoin="round"
119+
strokeWidth={2}
120+
d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"
121+
/>
122+
</svg>
123+
);
124+
}

0 commit comments

Comments
 (0)