diff --git a/src/components/FileExplorer.tsx b/src/components/FileExplorer.tsx index 13d36fc85..888e2dcf4 100644 --- a/src/components/FileExplorer.tsx +++ b/src/components/FileExplorer.tsx @@ -8,6 +8,7 @@ import svelteIconUrl from '~/images/file-icons/svelte.svg?url' import vueIconUrl from '~/images/file-icons/vue.svg?url' import markoIconUrl from '~/images/file-icons/marko.svg?url' import emberIconUrl from '~/images/ember-logo.svg?url' +import octaneIconUrl from '~/images/octane-logo.svg?url' import textIconUrl from '~/images/file-icons/txt.svg?url' import type { GitHubFileNode } from '~/utils/documents.server' import { twMerge } from 'tailwind-merge' @@ -19,6 +20,8 @@ const getFileIconPath = (filename: string) => { case 'ts': case 'tsx': return typescriptIconUrl + case 'tsrx': + return octaneIconUrl case 'js': case 'jsx': return javascriptIconUrl diff --git a/src/components/markdown/codeBlock.shared.tsx b/src/components/markdown/codeBlock.shared.tsx index ffbbdcc30..61a047d11 100644 --- a/src/components/markdown/codeBlock.shared.tsx +++ b/src/components/markdown/codeBlock.shared.tsx @@ -82,6 +82,7 @@ export function getCodeBlockLanguageFromFilePath(filePath: string) { } if (['cts', 'mts'].includes(ext)) return 'ts' + if (ext === 'tsrx') return 'tsx' if (['cjs', 'mjs'].includes(ext)) return 'js' if (ext === 'gts') return 'ts' if (ext === 'gjs') return 'js' diff --git a/src/images/octane-logo.svg b/src/images/octane-logo.svg new file mode 100644 index 000000000..7598b95f3 --- /dev/null +++ b/src/images/octane-logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/libraries/frameworks.tsx b/src/libraries/frameworks.tsx index c4214b9a8..665abe102 100644 --- a/src/libraries/frameworks.tsx +++ b/src/libraries/frameworks.tsx @@ -4,6 +4,7 @@ import emberLogo from '../images/ember-logo.svg' import jsLogo from '../images/js-logo.svg' import litLogo from '../images/lit-logo.svg' import markoLogo from '../images/marko-logo.svg' +import octaneLogo from '../images/octane-logo.svg' import qwikLogo from '../images/qwik-logo.svg' import preactLogo from '../images/preact-logo.svg' import reactLogo from '../images/react-logo.svg' @@ -69,6 +70,13 @@ export const frameworkOptions = [ color: 'bg-cyan-500', fontColor: 'text-cyan-500', }, + { + label: 'Octane', + value: 'octane', + logo: octaneLogo, + color: 'bg-rose-500', + fontColor: 'text-rose-500', + }, { label: 'Qwik', value: 'qwik', diff --git a/src/libraries/libraries.ts b/src/libraries/libraries.ts index 09bb239b2..0080b0e7c 100644 --- a/src/libraries/libraries.ts +++ b/src/libraries/libraries.ts @@ -300,6 +300,7 @@ export const table: LibrarySlim = { frameworks: [ 'angular', 'ember', + 'octane', 'react', 'preact', 'solid', @@ -474,7 +475,16 @@ export const store: LibrarySlim = { 'The immutable-reactive data store that powers the core of TanStack libraries and their framework adapters.', badge: 'alpha', repo: 'tanstack/store', - frameworks: ['react', 'preact', 'solid', 'svelte', 'vue', 'angular', 'lit'], + frameworks: [ + 'react', + 'preact', + 'solid', + 'svelte', + 'vue', + 'angular', + 'lit', + 'octane', + ], corePackageName: '@tanstack/store', npmPackageNames: ['@tanstack/store'], latestVersion: 'v0', diff --git a/src/libraries/types.ts b/src/libraries/types.ts index 15fb0bfe1..4af16e416 100644 --- a/src/libraries/types.ts +++ b/src/libraries/types.ts @@ -9,6 +9,7 @@ export type Framework = | 'ember' | 'lit' | 'marko' + | 'octane' | 'preact' | 'qwik' | 'react' diff --git a/src/routes/_library/$libraryId/$version.docs.framework.$framework.examples.$.tsx b/src/routes/_library/$libraryId/$version.docs.framework.$framework.examples.$.tsx index 1f8e007bd..e40db2ccb 100644 --- a/src/routes/_library/$libraryId/$version.docs.framework.$framework.examples.$.tsx +++ b/src/routes/_library/$libraryId/$version.docs.framework.$framework.examples.$.tsx @@ -487,7 +487,13 @@ function determineStartingFilePath( const preferenceFiles = new Set([ getExampleStartingFileName(framework, libraryId), ...['__root', 'App', 'main', 'index', 'page', 'action'] - .map((name) => [`${name}.tsx`, `${name}.ts`, `${name}.js`, `${name}.jsx`]) + .map((name) => [ + `${name}.tsrx`, + `${name}.tsx`, + `${name}.ts`, + `${name}.js`, + `${name}.jsx`, + ]) .flat(), 'README.md', ]) diff --git a/src/utils/llms.ts b/src/utils/llms.ts index 517276016..6015eb7f4 100644 --- a/src/utils/llms.ts +++ b/src/utils/llms.ts @@ -40,6 +40,7 @@ const frameworkLabels: Record = { ember: 'Ember', lit: 'Lit', marko: 'Marko', + octane: 'Octane', preact: 'Preact', qwik: 'Qwik', react: 'React', diff --git a/src/utils/npm-packages.ts b/src/utils/npm-packages.ts index c84be6bdf..4503d3d2b 100644 --- a/src/utils/npm-packages.ts +++ b/src/utils/npm-packages.ts @@ -31,6 +31,7 @@ export const frameworkMeta: Record = alpine: { name: 'Alpine', color: '#77C1D2' }, marko: { name: 'Marko', color: '#44bfef' }, ember: { name: 'Ember', color: '#E04E39' }, + octane: { name: 'Octane', color: '#FF415A' }, qwik: { name: 'Qwik', color: '#18B6F6' }, vanilla: { name: 'Vanilla', color: '#F7DF1E' }, } diff --git a/src/utils/sandbox.ts b/src/utils/sandbox.ts index 8fd0d5b4f..51c2379ed 100644 --- a/src/utils/sandbox.ts +++ b/src/utils/sandbox.ts @@ -31,9 +31,11 @@ export function getExampleStartingFileName( ? 'svelte' : framework === 'vue' ? 'vue' - : ['angular', 'lit'].includes(framework) - ? 'ts' - : 'tsx' + : framework === 'octane' + ? 'tsrx' + : ['angular', 'lit'].includes(framework) + ? 'ts' + : 'tsx' return `${file}.${ext}` as const } diff --git a/tests/code-highlighting.test.ts b/tests/code-highlighting.test.ts index cda46e666..e456d3740 100644 --- a/tests/code-highlighting.test.ts +++ b/tests/code-highlighting.test.ts @@ -3,6 +3,11 @@ import test from 'node:test' import { defaultHighlighter } from '@tanstack/highlight' import { renderCodeFence } from '@tanstack/highlight/markdown' import { createThemeBaseCss } from '@tanstack/highlight/theme' +import { getCodeBlockLanguageFromFilePath } from '../src/components/markdown/codeBlock.shared' + +test('TSRX files use TypeScript JSX highlighting', () => { + assert.equal(getCodeBlockLanguageFromFilePath('src/main.tsrx'), 'tsx') +}) test('inline diff notation renders as line decorations', () => { const rendered = renderCodeFence( diff --git a/tests/octane-framework-support.test.ts b/tests/octane-framework-support.test.ts new file mode 100644 index 000000000..b3e852827 --- /dev/null +++ b/tests/octane-framework-support.test.ts @@ -0,0 +1,23 @@ +import assert from 'node:assert/strict' +import { libraries, store, table } from '../src/libraries/libraries' +import { getFrameworkPackageName } from '../src/libraries/frameworkSupport' + +assert.deepEqual( + libraries + .filter((library) => library.frameworks.includes('octane')) + .map((library) => library.id), + ['table', 'store'], + 'only Table and Store advertise Octane support', +) + +assert.equal( + getFrameworkPackageName('octane', table.id, table), + '@tanstack/octane-table', +) + +assert.equal( + getFrameworkPackageName('octane', store.id, store), + '@tanstack/octane-store', +) + +console.log('Octane framework support tests passed') diff --git a/tests/repo-path.test.ts b/tests/repo-path.test.ts index eaf8434d5..b990d1ebc 100644 --- a/tests/repo-path.test.ts +++ b/tests/repo-path.test.ts @@ -61,4 +61,10 @@ assert.equal( 'Router examples default to main.tsx when directory contents are unavailable', ) +assert.equal( + getExampleStartingPath('octane', 'table'), + 'src/main.tsrx', + 'Octane examples default to main.tsrx', +) + console.log('repo-path tests passed')