Skip to content

Commit

Permalink
Better embed support
Browse files Browse the repository at this point in the history
  • Loading branch information
skryukov committed Mar 10, 2024
1 parent 154efa1 commit 6089cfa
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 75 deletions.
129 changes: 69 additions & 60 deletions src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { $editor } from "../../stores/editor.ts";
import useComponentVisible from "../../useComponentVisible.ts";

import cs from "./Header.module.css";
import { getQueryParam } from "../../fsInitializer.ts";

export const Header = () => {
const { isOpen } = useStore($menu);
Expand All @@ -31,41 +32,45 @@ export const Header = () => {
<button className={cs.headerMenuButton} onClick={toggleMenu}>
{isOpen ? <VscClose size={16} /> : <VscMenu size={16} />}
</button>
{showFork && (
<button
className={`${cs.forkButton} ${canFork ? "" : cs.disabledButton}`}
title={canFork ? "Fork this Gist" : "You need to be logged in to fork this Gist"}
disabled={!canFork}
onClick={() => forkGist(openedGist.id)}
>
<VscRepoForked /> Fork
</button>
)}
{(showSave) && (
<button
className={`${cs.saveButton} ${canSave ? "" : cs.disabledButton}`}
title={canSave ? "Create a Gist" : "You need to be logged in to create a Gist"}
disabled={!canSave}
onClick={saveGist}
>
<VscSave /> Create Gist
</button>
)}
{showUpdate && (
<button
className={`${cs.saveButton} ${canUpdate ? "" : cs.disabledButton}`}
title={canUpdate ? "Update Gist" : "No changes to save"}
disabled={!canUpdate}
onClick={() => {
updateGist(openedGist.id);
}}
>
<VscSave /> Save
</button>
{getQueryParam("embed") !== "1" && (
<>
{showFork && (
<button
className={`${cs.forkButton} ${canFork ? "" : cs.disabledButton}`}
title={canFork ? "Fork this Gist" : "You need to be logged in to fork this Gist"}
disabled={!canFork}
onClick={() => forkGist(openedGist.id)}
>
<VscRepoForked /> Fork
</button>
)}
{showSave && (
<button
className={`${cs.saveButton} ${canSave ? "" : cs.disabledButton}`}
title={canSave ? "Create a Gist" : "You need to be logged in to create a Gist"}
disabled={!canSave}
onClick={saveGist}
>
<VscSave /> Create Gist
</button>
)}
{showUpdate && (
<button
className={`${cs.saveButton} ${canUpdate ? "" : cs.disabledButton}`}
title={canUpdate ? "Update Gist" : "No changes to save"}
disabled={!canUpdate}
onClick={() => {
updateGist(openedGist.id);
}}
>
<VscSave /> Save
</button>
)}
<div className={cs.gistLoading}>
{gistLoading && <VscLoading size={20} />}
</div>
</>
)}
<div className={cs.gistLoading}>
{gistLoading && <VscLoading size={20} />}
</div>
</div>

<div className={cs.logoContainer}>
Expand All @@ -74,32 +79,36 @@ export const Header = () => {
</div>

<div className={cs.links}>
{currentUser.id ? (
<div className={cs.userContainer}
onClick={() => setIsComponentVisible(true)}
ref={ref}
>
<img className={cs.avatar} src={currentUser.avatarUrl} alt={currentUser.username} />
<div className={`${cs.userMenu} ${isComponentVisible ? cs.show : ""}`}>
<button className={cs.signOutButton} onClick={signOut}>Sign out</button>
</div>
</div>
) : (
<button className={cs.SignInButton} onClick={() => {
const bc = new BroadcastChannel("oauth");
bc.onmessage = (event) => {
const searchParams = new URLSearchParams(event.data);
if (searchParams.get("state") === state) {
$oauth.setKey("code", searchParams.get("code") || undefined);
$oauth.setKey("error", searchParams.get("error") || undefined);
bc.close();
}
bc.close();
};
window.open(`https://github.com/login/oauth/authorize?client_id=${import.meta.env.VITE_GITHUB_CLIENT_ID}&scope=gist&state=${state}`, "popup", "popup=true, width=600, height=400");
}}>
<VscGithub size={16} /> Sign in
</button>
{getQueryParam("embed") === "1" && (
<>
{currentUser.id ? (
<div className={cs.userContainer}
onClick={() => setIsComponentVisible(true)}
ref={ref}
>
<img className={cs.avatar} src={currentUser.avatarUrl} alt={currentUser.username} />
<div className={`${cs.userMenu} ${isComponentVisible ? cs.show : ""}`}>
<button className={cs.signOutButton} onClick={signOut}>Sign out</button>
</div>
</div>
) : (
<button className={cs.SignInButton} onClick={() => {
const bc = new BroadcastChannel("oauth");
bc.onmessage = (event) => {
const searchParams = new URLSearchParams(event.data);
if (searchParams.get("state") === state) {
$oauth.setKey("code", searchParams.get("code") || undefined);
$oauth.setKey("error", searchParams.get("error") || undefined);
bc.close();
}
bc.close();
};
window.open(`https://github.com/login/oauth/authorize?client_id=${import.meta.env.VITE_GITHUB_CLIENT_ID}&scope=gist&state=${state}`, "popup", "popup=true, width=600, height=400");
}}>
<VscGithub size={16} /> Sign in
</button>
)}
</>
)}
</div>
</header>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Output/SettingsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function findDirectory(dir: DirectoryContents, s: string) {
let current = dir;
for (const part of parts) {

if (!("contents" in current[part])) {
if (!(current[part] && "contents" in current[part])) {
return undefined;
}
current = (current[part] as MarshaledDirectory).contents;
Expand Down
41 changes: 28 additions & 13 deletions src/fsInitializer.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
import importFromGist from "./gist.ts";

export const getQueryParam = (key: string) => {
const url = new URL(window.location.href);
const params = new URLSearchParams(url.search);
return params.get(key);
};

const defaultGem = "octokit";

const mainRbHeader = (gem: string | null) => `# This is a Ruby WASI playground
const description = `# This is a Ruby WASI playground
# You can run any Ruby code here and see the result
# You can also install gems using a Gemfile and the "Bundle install" button.
${gem ? `\nrequire "${gem}"\n` : ""}`;
# You can also install gems using a Gemfile and the "Bundle install" button.`;

const mainRbHeader = (gem: string | null) => {
const strings: string[] = [];
if (getQueryParam("embed") !== "1") {
strings.push(description);
}
if (gem) {
strings.push(`require "${gem.split("@")[0]}"\n`);
}

return strings.join("\n");
};

const mainRb = `${mainRbHeader(defaultGem)}
# RunRuby.dev comes with a WASI-compatible Faraday adapter
Expand All @@ -21,26 +38,20 @@ user = client.user("matz")
pp({login: user.login, name: user.name, company: user.company})
`;

export const getQueryParam = (key: string) => {
const url = new URL(window.location.href);
const params = new URLSearchParams(url.search);
return params.get(key);
};

const gemfileContents = (gem: string) => (
`source "https://rubygems.org"
gem "${gem}"
gem "${gem.split("@")[0]}", "${gem.split("@")[1] || ">= 0"}"
`
);

const buildStarter = ({ gem, main }: { gem: string | null, main: string }) => {
const result = [
{ filename: "main.rb", content: main },
{ filename: "main.rb", content: main }
];

if (gem) {
result.push({ filename: "Gemfile", content: gemfileContents(gem) })
result.push({ filename: "Gemfile", content: gemfileContents(gem) });
}

return result;
Expand All @@ -62,6 +73,10 @@ export const composeInitialFS = async () => {
return buildMainRB();
};

export const urlSafeAtob = (str: string) => {
return decodeURIComponent(atob(str.replace(/-/g, "+").replace(/_/g, "/")));
};

const buildMainRB = () => {
const initialGem = getQueryParam("gem");
const initialCode = getQueryParam("code");
Expand All @@ -70,7 +85,7 @@ const buildMainRB = () => {
return { files: buildStarter({ gem: defaultGem, main: mainRb }) };
}

const code = initialCode ? decodeURIComponent(atob(initialCode)) : "";
const code = initialCode ? urlSafeAtob(initialCode) : "";
const main = mainRbHeader(initialGem) + "\n" + code;

return { files: buildStarter({ gem: initialGem, main }) };
Expand Down
1 change: 0 additions & 1 deletion src/stores/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const THEME_KEY = "theme";
export const $theme = atom<Theme>("system");

export const setTheme = action($theme, "set", (store, theme: Theme) => {

document.documentElement.setAttribute(THEME_KEY, theme);
store.set(theme);
localStorage.setItem(THEME_KEY, theme);
Expand Down

0 comments on commit 6089cfa

Please sign in to comment.