Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deploy #253

Merged
merged 14 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
"image": "mcr.microsoft.com/devcontainers/base:jammy",
"features": {
"ghcr.io/devcontainers/features/node:1": {},
"ghcr.io/devcontainers/features/rust:1": {},
"devwasm.azurecr.io/dev-wasm/dev-wasm-feature/rust-wasi:0": {},
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},

Expand All @@ -19,8 +17,6 @@

// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": {
"submodule": "git submodule update --init --recursive",
"wasm-pack": "curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh",
"yarn": "yarn",
"deno": "curl -fsSL https://deno.land/install.sh | sh"
},
Expand Down
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
NEXT_PUBLIC_SUPABASE_URL=https://hkisrufjmjfdgyqbbcwa.supabase.co
NEXT_PUBLIC_SUPABASE_HOSTNAME=hkisrufjmjfdgyqbbcwa.supabase.co
NEXT_PUBLIC_SUPABASE_PROJECT_ID=hkisrufjmjfdgyqbbcwa
NEXT_PUBLIC_SUPABASE_PUBLIC_API_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImhraXNydWZqbWpmZGd5cWJiY3dhIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTE0NTU3MTQsImV4cCI6MTk2NzAzMTcxNH0.4TTxpdJel1NihwIA3KDtcPtaZdbvMwOG6tl3cm7bbp8
5 changes: 3 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@
"missingExports": true,
"unusedExports": true,
"ignoreExports": [
"pages",
"src/pages",
"app/*.tsx",
"app/**/page.tsx",
"app/**/route.ts",
"theme/themeModule.ts",
"next-env.d.ts",
"next.config.mjs"
Expand Down
14 changes: 0 additions & 14 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,6 @@ jobs:
steps:
- name: Checkout from repo
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
target: wasm32-unknown-unknown
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: wgpu-compute-toy
- run: cargo install wasm-pack --force
- uses: actions/setup-node@v4
with:
node-version-file: .node-version
Expand Down
14 changes: 0 additions & 14 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,6 @@ jobs:
steps:
- name: Checkout from repo
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
target: wasm32-unknown-unknown
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: wgpu-compute-toy
- run: cargo install wasm-pack --force
- uses: actions/setup-node@v4
with:
node-version-file: .node-version
Expand Down
Empty file removed .gitmodules
Empty file.
3 changes: 1 addition & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"githubPullRequests.ignoredPullRequestBranches": [
"master"
],
"rust-analyzer.cargo.target": "wasm32-unknown-unknown"
]
}
17 changes: 1 addition & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,10 @@ This is the source code of the [compute.toys](https://compute.toys) website.

## Development

Make sure you install these tools:

- [Yarn](https://yarnpkg.com/getting-started/install)
- [Rust](https://www.rust-lang.org/tools/install)
- [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/)

To install dependencies:

- make sure you've cloned submodules: `git submodule update --init --recursive`
- run `yarn`
- run [`yarn`](https://yarnpkg.com/getting-started/install)

To start the development server, run `yarn dev`, or use the debug configuration in VS Code.

Expand All @@ -36,15 +30,6 @@ You should also set `api_url` in `supabase/config.toml` to the same address.

A local test user is available to login with username `[email protected]` and password `pass`

## Standalone Editor

By default, the development environment will connect to the public API for the compute.toys website.
If you'd prefer to develop just the editor component, without any of the account-based sharing features,
delete the `pages` directory before starting the server.

If you have any difficulties with Next.js switching between the two configurations,
clear the cache by deleting the `.next` directory and try again.

---

This project is tested with BrowserStack
Binary file added app/apple-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions app/auth/confirm/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { type EmailOtpType } from '@supabase/supabase-js';
import { createClient } from 'lib/supabase/server';
import { redirect } from 'next/navigation';
import { type NextRequest } from 'next/server';

export const runtime = 'edge';

export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const token_hash = searchParams.get('token_hash');
const type = searchParams.get('type') as EmailOtpType | null;
const next = searchParams.get('next') ?? '/';

if (token_hash && type) {
const supabase = await createClient();

const { error } = await supabase.auth.verifyOtp({
type,
token_hash
});
if (!error) {
// redirect user to specified redirect URL or root of app
redirect(next);
}
}

// redirect the user to an error page with some instructions
redirect('/error');
}
15 changes: 15 additions & 0 deletions app/embed/[id]/embed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use client';
import Editor from 'components/editor/editor';
import { useShader } from 'lib/view/client';

export default function Index(props) {
useShader(props.shader);
return (
<div>
<style>{`
body { overflow: hidden; }
`}</style>
<Editor embed={true} />
</div>
);
}
16 changes: 16 additions & 0 deletions app/embed/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { createClient } from 'lib/supabase/server';
import { fetchShader } from 'lib/view/server';
import { notFound } from 'next/navigation';
import EmbedShader from './embed';

export const runtime = 'edge';

export default async function ViewShaderPage({ params }) {
const supabase = await createClient();
let { id } = await params;
id = Number(id);
if (Number.isNaN(id)) notFound();
const shader = await fetchShader(supabase, id);
if (!shader) notFound();
return <EmbedShader id={id} shader={shader} />;
}
7 changes: 7 additions & 0 deletions app/error/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use client';

export const runtime = 'edge';

export default function ErrorPage() {
return <p>Sorry, something went wrong</p>;
}
Binary file added app/favicon.ico
Binary file not shown.
Binary file added app/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import CssBaseline from '@mui/material/CssBaseline';
import { ThemeProvider } from '@mui/material/styles';
import Footer from 'components/footer';
import { ShadowCanvas } from 'components/global/shadowcanvas';
import TopBar from 'components/global/topbar';
import { createClient } from 'lib/supabase/server';
import { WindowManagementProvider } from 'lib/util/draggablewindowscontext';
import { NavigationGuardProvider } from 'next-navigation-guard';
import { theme } from 'theme/theme';

const Providers = ({ children }: { children: React.ReactNode }) => {
return (
<WindowManagementProvider>
<NavigationGuardProvider>
<ThemeProvider theme={theme}>{children}</ThemeProvider>
</NavigationGuardProvider>
</WindowManagementProvider>
);
};

export default async function RootLayout({
// Layouts must accept a children prop.
// This will be populated with nested layouts or pages
children
}: {
children: React.ReactNode;
}) {
const supabase = await createClient();
const { data, error } = await supabase.auth.getUser();
return (
<html lang="en">
<body>
<Providers>
<ShadowCanvas />
<CssBaseline />
<TopBar user={error || !data?.user ? null : data.user} />
{children}
<Footer />
</Providers>
</body>
</html>
);
}
68 changes: 68 additions & 0 deletions app/list/[page]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { SupabaseClient } from '@supabase/supabase-js';
import ShaderList from 'components/shaderlist';
import { createClient } from 'lib/supabase/server';
import { notFound } from 'next/navigation';

export const runtime = 'edge';

const SHADERS_PER_PAGE = 12;

const getPagination = (page: number, size: number) => {
const from = (page - 1) * size;
const to = from + size - 1;
return { from, to };
};

const getTotalCount = async (supabase: SupabaseClient): Promise<number> => {
const { error, count } = await supabase
.from('shader')
.select('*', { count: 'exact', head: true })
.eq('visibility', 'public');
if (error || count === null) return 0;
return count;
};

async function getShaders(supabase: SupabaseClient, page: number) {
// context.res.setHeader('Cache-Control', 'public, s-maxage=10, stale-while-revalidate=59');

const { from, to } = getPagination(page, SHADERS_PER_PAGE);
const { data, error } = await supabase
.from('shader')
.select(
`
id,
name,
profile:author (
id,
username,
avatar_url
),
thumb_url
`
)
.order('created_at', { ascending: false })
.range(from, to)
.eq('visibility', 'public');

const totalCount = await getTotalCount(supabase);
const numPages = Math.ceil(totalCount / SHADERS_PER_PAGE);

if (page < 1 || page > numPages || Number.isNaN(page)) notFound();

return {
props: {
shaders: data ?? [],
totalCount,
numPages,
error,
page
}
};
}

export default async function ShaderListPage({ params }) {
const supabase = await createClient();
const { page } = await params;
const { props } = await getShaders(supabase, Number(page));
return <ShaderList {...props} />;
}
61 changes: 61 additions & 0 deletions app/login/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use server';

import { EmailOtpType } from '@supabase/supabase-js';
import { createClient } from 'lib/supabase/server';
import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';

export async function login(formData: FormData) {
const supabase = await createClient();

// type-casting here for convenience
// in practice, you should validate your inputs
const data = {
email: formData.get('email') as string
};

const { error } = await supabase.auth.signInWithOtp(data);

if (error) {
throw error;
}

// revalidatePath('/', 'layout');

const email = encodeURIComponent(data.email);
redirect(`/login/otp?email=${email}`);
}

export async function verify(formData: FormData) {
const supabase = await createClient();

// type-casting here for convenience
// in practice, you should validate your inputs
const data = {
email: formData.get('email') as string,
token: formData.get('token') as string,
type: 'email' as EmailOtpType
};

const { error } = await supabase.auth.verifyOtp(data);

if (error) {
throw error;
}

revalidatePath('/list/1', 'layout');
redirect('/list/1');
}

export async function logout() {
const supabase = await createClient();

const { error } = await supabase.auth.signOut();

if (error) {
throw error;
}

revalidatePath('/list/1', 'layout');
redirect('/list/1');
}
23 changes: 23 additions & 0 deletions app/login/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use client';

import Box from '@mui/material/Box/Box';
import Button from '@mui/material/Button/Button';
import { Item } from 'theme/theme';

export default function Error({
error,
reset
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<Box sx={{ p: 4 }}>
<Item sx={{ color: 'white' }}>
<h2>Something went wrong!</h2>
<pre>{error.message}</pre>
<Button onClick={reset}>Try again</Button>
</Item>
</Box>
);
}
Loading