Skip to content
Draft
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
68 changes: 38 additions & 30 deletions apps/typegpu-docs/src/components/CodeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,57 @@ import Editor, {
type OnMount,
} from '@monaco-editor/react';
import type { editor } from 'monaco-editor';
import { getDefaultStore } from 'jotai';
import { entries, filter, fromEntries, isTruthy, map, pipe } from 'remeda';
import { SANDBOX_MODULES } from '../utils/examples/sandboxModules.ts';
import { sandboxModulesAtom } from '../utils/examples/sandboxModules.ts';
import type { ExampleSrcFile } from '../utils/examples/types.ts';
import { tsCompilerOptions } from '../utils/liveEditor/embeddedTypeScript.ts';

function handleEditorWillMount(monaco: Monaco) {
// NOTE: This is not recommended, as the default store is not always the one you want,
// but in this particular case, it's totally fine.
const store = getDefaultStore();
const tsDefaults = monaco?.languages.typescript.typescriptDefaults;

const reroutes = pipe(
entries(SANDBOX_MODULES),
map(([key, moduleDef]) => {
if ('reroute' in moduleDef.typeDef) {
return [key, [moduleDef.typeDef.reroute]] as [string, string[]];
}
return null;
}),
filter(isTruthy),
fromEntries(),
);
(async () => {
const SANDBOX_MODULES = await store.get(sandboxModulesAtom);

for (const [moduleKey, moduleDef] of entries(SANDBOX_MODULES)) {
if ('content' in moduleDef.typeDef) {
tsDefaults.addExtraLib(
moduleDef.typeDef.content,
moduleDef.typeDef.filename,
);
const reroutes = pipe(
entries(SANDBOX_MODULES),
map(([key, moduleDef]) => {
if ('reroute' in moduleDef.typeDef) {
return [key, [moduleDef.typeDef.reroute]] as [string, string[]];
}
return null;
}),
filter(isTruthy),
fromEntries(),
);

if (
moduleDef.typeDef.filename &&
moduleDef.typeDef.filename !== moduleKey // the redirect is not a no-op
) {
reroutes[moduleKey] = [
...(reroutes[moduleKey] ?? []),
for (const [moduleKey, moduleDef] of entries(SANDBOX_MODULES)) {
if ('content' in moduleDef.typeDef) {
tsDefaults.addExtraLib(
moduleDef.typeDef.content,
moduleDef.typeDef.filename,
];
);

if (
moduleDef.typeDef.filename &&
moduleDef.typeDef.filename !== moduleKey // the redirect is not a no-op
) {
reroutes[moduleKey] = [
...(reroutes[moduleKey] ?? []),
moduleDef.typeDef.filename,
];
}
}
}
}

tsDefaults.setCompilerOptions({
...tsCompilerOptions,
paths: reroutes,
});
tsDefaults.setCompilerOptions({
...tsCompilerOptions,
paths: reroutes,
});
})();
}

function handleEditorOnMount(editor: editor.IStandaloneCodeEditor) {
Expand Down
5 changes: 3 additions & 2 deletions apps/typegpu-docs/src/components/ExampleView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ function useExample(
}

export function ExampleView({ example }: Props) {
const { tsFiles, tsImport, htmlFile } = example;
const { tsImport, contentAtom } = example;
const { htmlFile, tsFiles } = useAtomValue(contentAtom);

const [snackbarText, setSnackbarText] = useAtom(currentSnackbarAtom);
const [currentFilePath, setCurrentFilePath] = useState<string>('index.ts');
Expand All @@ -88,7 +89,7 @@ export function ExampleView({ example }: Props) {
return;
}
exampleHtmlRef.current.innerHTML = htmlFile.content;
}, [htmlFile]);
}, [htmlFile.content]);

useExample(tsImport, setSnackbarText); // live example
useResizableCanvas(exampleHtmlRef);
Expand Down
66 changes: 37 additions & 29 deletions apps/typegpu-docs/src/components/translator/lib/editorConfig.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { entries, filter, fromEntries, isTruthy, map, pipe } from 'remeda';
import type { Monaco } from '@monaco-editor/react';
import { SANDBOX_MODULES } from '../../../utils/examples/sandboxModules.ts';
import { sandboxModulesAtom } from '../../../utils/examples/sandboxModules.ts';
import { tsCompilerOptions } from '../../../utils/liveEditor/embeddedTypeScript.ts';
import { getDefaultStore } from 'jotai';

export const LANGUAGE_MAP: Record<string, string> = {
wgsl: 'wgsl',
Expand Down Expand Up @@ -38,41 +39,48 @@ export const readOnlyEditorOptions = {
};

export function setupMonacoEditor(monaco: Monaco) {
// NOTE: This is not recommended, as the default store is not always the one you want,
// but in this particular case, it's totally fine.
const store = getDefaultStore();
const tsDefaults = monaco?.languages.typescript.typescriptDefaults;

const reroutes = pipe(
entries(SANDBOX_MODULES),
map(([key, moduleDef]) => {
if ('reroute' in moduleDef.typeDef) {
return [key, [moduleDef.typeDef.reroute]] as [string, string[]];
}
return null;
}),
filter(isTruthy),
fromEntries(),
);
(async () => {
const SANDBOX_MODULES = await store.get(sandboxModulesAtom);

for (const [moduleKey, moduleDef] of entries(SANDBOX_MODULES)) {
if ('content' in moduleDef.typeDef) {
tsDefaults.addExtraLib(
moduleDef.typeDef.content,
moduleDef.typeDef.filename,
);
const reroutes = pipe(
entries(SANDBOX_MODULES),
map(([key, moduleDef]) => {
if ('reroute' in moduleDef.typeDef) {
return [key, [moduleDef.typeDef.reroute]] as [string, string[]];
}
return null;
}),
filter(isTruthy),
fromEntries(),
);

if (
moduleDef.typeDef.filename &&
moduleDef.typeDef.filename !== moduleKey
) {
reroutes[moduleKey] = [
...(reroutes[moduleKey] ?? []),
for (const [moduleKey, moduleDef] of entries(SANDBOX_MODULES)) {
if ('content' in moduleDef.typeDef) {
tsDefaults.addExtraLib(
moduleDef.typeDef.content,
moduleDef.typeDef.filename,
];
);

if (
moduleDef.typeDef.filename &&
moduleDef.typeDef.filename !== moduleKey
) {
reroutes[moduleKey] = [
...(reroutes[moduleKey] ?? []),
moduleDef.typeDef.filename,
];
}
}
}
}

tsDefaults.setCompilerOptions({
...tsCompilerOptions,
paths: reroutes,
tsDefaults.setCompilerOptions({
...tsCompilerOptions,
paths: reroutes,
});
});
}
52 changes: 32 additions & 20 deletions apps/typegpu-docs/src/examples/exampleContent.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pathe from 'pathe';
import * as R from 'remeda';
import { atom } from 'jotai';
import type {
Example,
ExampleMetadata,
Expand Down Expand Up @@ -46,20 +47,27 @@ function pathToExampleKey(path: string): string {
}

function globToExampleFiles(
record: Record<string, string>,
): Record<string, ExampleSrcFile[]> {
record: Record<string, () => Promise<string>>,
): Record<
string,
({ exampleKey: string; file: () => Promise<ExampleSrcFile> })[]
> {
return R.pipe(
record,
R.mapValues((content, key): ExampleSrcFile => {
R.mapValues((content, key) => {
const pathRelToExamples = pathe.relative('./', key);
const categoryDir = pathRelToExamples.split('/')[0];
const exampleDir = pathRelToExamples.split('/')[1];
const examplePath = pathe.join(categoryDir, exampleDir);
const exampleKey = pathToExampleKey(key);

return {
exampleKey: pathToExampleKey(key),
path: pathe.relative(examplePath, key),
content,
exampleKey,
file: async () => ({
exampleKey,
path: pathe.relative(examplePath, key),
content: await content(),
}),
};
}),
R.values(),
Expand All @@ -76,37 +84,32 @@ const metaFiles = R.pipe(
);

const readonlyTsFiles = R.pipe(
import.meta.glob('./**/*.ts', {
import.meta.glob<string>('./**/*.ts', {
query: 'raw',
eager: true,
import: 'default',
}) as Record<string, string>,
}),
globToExampleFiles,
);

const tsFilesImportFunctions = R.pipe(
import.meta.glob('./**/index.ts') as Record<
string,
() => Promise<unknown>
>,
import.meta.glob('./**/index.ts'),
R.mapKeys(pathToExampleKey),
);

const htmlFiles = R.pipe(
import.meta.glob('./**/index.html', {
import.meta.glob<string>('./**/index.html', {
query: 'raw',
eager: true,
import: 'default',
}) as Record<string, string>,
}),
globToExampleFiles,
);

const thumbnailFiles = R.pipe(
import.meta.glob('./**/thumbnail.png', {
import.meta.glob<string | [string, string]>('./**/thumbnail.png', {
eager: true,
import: 'default',
query: 'w=512;1024',
}) as Record<string, string | [string, string]>,
}),
R.mapKeys(pathToExampleKey),
R.mapValues((
value,
Expand All @@ -127,9 +130,18 @@ export const examples = R.pipe(
({
key,
metadata: value,
tsFiles: readonlyTsFiles[key] ?? [],
contentAtom: atom(async () => {
const [htmlFile, ...tsFiles] = await Promise.all([
htmlFiles[key]?.[0].file(),
...readonlyTsFiles[key].map((file) => file.file()),
]);

return {
htmlFile,
tsFiles,
};
}),
tsImport: () => noCacheImport(tsFilesImportFunctions[key]),
htmlFile: htmlFiles[key]?.[0] ?? '',
thumbnails: thumbnailFiles[key],
}) satisfies Example
),
Expand Down
Loading
Loading