// The viewer: the upstream's React UI (its Vite, React and Linaria setup from vite.config.ts) with this folder's entry, // as static files with relative paths and no network: one script, one stylesheet, no CDN, no fonts to fetch. The art // pack (viewer/art/, built by src/art.py) is plain files beside them, linked from index.html. // // The look is 无名杀's (viewer/noname/): this folder's own table over the upstream's hooks and action building. When the // upstream's own components (its prompts, action bar and hand) import these modules, they get this folder's instead: // the image lookups (the art pack), the flying cards and the card face (drawn as 无名杀's; a card you play leaves your // hand for the middle of the table), and the style sheet (the same class names, restyled). import path from 'node:path'; import { defineConfig, type Plugin } from 'vite'; import react from '@vitejs/plugin-react'; import wyw from '@wyw-in-js/vite'; const NONAME = path.resolve('shoal/viewer/noname'); const SWAPS: Record = { 'src/client/assets/imageAssets': 'imageAssets.ts', 'src/client/utils/cardMoveAnimation': 'flyCards.ts', 'src/client/utils/cardFlyAnimation': 'flyCards.ts', 'src/client/components/CardFace': 'CardFace.tsx', 'src/client/components/gameViewStyles/index': 'styles.ts', }; function swap(): Plugin { return { name: 'shoal-noname-swap', enforce: 'pre', async resolveId(source, importer, opts) { if (!importer || importer.startsWith(NONAME)) return null; const r = await this.resolve(source, importer, { ...opts, skipSelf: true }); const id = r?.id.replace(/\.tsx?$/, ''); const hit = id && Object.keys(SWAPS).find((k) => id.endsWith(k)); return hit ? path.join(NONAME, SWAPS[hit]) : null; }, }; } export default defineConfig({ root: 'shoal/viewer', base: './', publicDir: false, plugins: [ swap(), react({ exclude: ['node_modules/**'] }), wyw({ sourceMap: false, displayName: false, exclude: ['node_modules/**'], evaluate: true, babelOptions: { presets: ['@babel/preset-typescript'] } }), ], build: { outDir: '../../dist/shoal-viewer', emptyOutDir: true, target: 'es2022', cssMinify: 'esbuild', rollupOptions: { output: { codeSplitting: false, entryFileNames: 'viewer.js', assetFileNames: 'viewer[extname]' } }, }, });