├── .npmrc ├── .prettierrc ├── apps └── official-website │ ├── .gitignore │ ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── mstile-70x70.png │ ├── favicon-16x16.png │ ├── favicon-194x194.png │ ├── favicon-32x32.png │ ├── mstile-144x144.png │ ├── mstile-150x150.png │ ├── mstile-310x150.png │ ├── mstile-310x310.png │ ├── apple-touch-icon.png │ ├── assets │ │ ├── vans-shoe.glb │ │ └── DamagedHelmet.glb │ ├── screenshot-mobile.png │ ├── draco │ │ ├── draco_decoder.wasm │ │ └── README.md │ ├── screenshot-desktop.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon-57x57.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-72x72.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon-114x114.png │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-144x144.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-precomposed.png │ ├── apple-touch-icon-57x57-precomposed.png │ ├── apple-touch-icon-60x60-precomposed.png │ ├── apple-touch-icon-72x72-precomposed.png │ ├── apple-touch-icon-76x76-precomposed.png │ ├── apple-touch-icon-114x114-precomposed.png │ ├── apple-touch-icon-120x120-precomposed.png │ ├── apple-touch-icon-144x144-precomposed.png │ ├── apple-touch-icon-152x152-precomposed.png │ ├── apple-touch-icon-180x180-precomposed.png │ ├── browserconfig.xml │ ├── sitemap.xml │ ├── site.webmanifest │ └── safari-pinned-tab.svg │ ├── src │ ├── vite-env.d.ts │ ├── pages │ │ ├── editor │ │ │ ├── index.ts │ │ │ ├── loading-overlay.tsx │ │ │ ├── color-picker.tsx │ │ │ ├── drop-zone.tsx │ │ │ ├── upload-info-dialog.tsx │ │ │ └── editor.tsx │ │ ├── contact.tsx │ │ └── help.tsx │ ├── components │ │ ├── assets │ │ │ ├── react-graphic.png │ │ │ ├── google-icon.tsx │ │ │ └── vectreal-logo.tsx │ │ ├── providers │ │ │ ├── index.ts │ │ │ ├── router-provider.tsx │ │ │ ├── theme-provider.tsx │ │ │ └── editor-provider.tsx │ │ ├── typography │ │ │ ├── typography-muted.tsx │ │ │ └── typography-lead.tsx │ │ ├── modal-close-button.tsx │ │ ├── title-section.tsx │ │ ├── footer.tsx │ │ ├── title-model-scene.tsx │ │ └── base-layout.tsx │ ├── lib │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── use-is-mobile.ts │ │ │ ├── use-init-ga.ts │ │ │ ├── use-media.ts │ │ │ └── use-accept-pattern.ts │ │ └── utils │ │ │ └── ga-utils.ts │ ├── app.tsx │ ├── main.tsx │ └── globals.css │ ├── .eslintignore │ ├── package.json │ ├── project.json │ ├── nginx.conf │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── tsconfig.app.json │ ├── Dockerfile │ ├── tailwind.config.js │ ├── vite.config.mts │ └── index.html ├── shared ├── src │ ├── index.ts │ ├── lib │ │ └── utils.ts │ └── components │ │ ├── skeleton.tsx │ │ ├── index.ts │ │ ├── default-spinner.tsx │ │ ├── label.tsx │ │ ├── textarea.tsx │ │ ├── input.tsx │ │ ├── progress.tsx │ │ ├── sonner.tsx │ │ ├── hero-highlight.tsx │ │ ├── badge.tsx │ │ ├── tooltip.tsx │ │ ├── popover.tsx │ │ ├── avatar.tsx │ │ ├── button.tsx │ │ ├── accordion.tsx │ │ ├── card.tsx │ │ ├── dialog.tsx │ │ ├── glowing-stars.tsx │ │ └── sheet.tsx ├── README.md ├── .babelrc ├── project.json ├── tsconfig.json ├── .eslintrc.json └── tsconfig.lib.json ├── .eslintignore ├── packages ├── viewer │ ├── src │ │ ├── index.ts │ │ ├── components │ │ │ ├── assets │ │ │ │ ├── types.ts │ │ │ │ ├── vectreal-logo.tsx │ │ │ │ ├── cross-icon.tsx │ │ │ │ └── info-icon.tsx │ │ │ ├── index.ts │ │ │ ├── spinner-wrapper.tsx │ │ │ ├── scene │ │ │ │ ├── index.ts │ │ │ │ ├── scene-model.tsx │ │ │ │ ├── scene-environment.tsx │ │ │ │ ├── scene-controls.tsx │ │ │ │ ├── scene-camera.tsx │ │ │ │ └── scene-grid.tsx │ │ │ └── info-popover.tsx │ │ └── styles.module.css │ ├── .babelrc │ ├── .storybook │ │ ├── preview.ts │ │ └── main.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── tsconfig.storybook.json │ ├── project.json │ ├── package.json │ ├── vite.config.ts │ └── .eslintrc.json └── hooks │ ├── src │ ├── use-export-model │ │ ├── index.ts │ │ ├── utils │ │ │ ├── index.ts │ │ │ ├── data-uri-to-blob.ts │ │ │ ├── file-helpers.ts │ │ │ └── export-handlers.ts │ │ ├── types.ts │ │ └── use-export-model.ts │ ├── use-optimize-model │ │ ├── index.ts │ │ ├── types.ts │ │ └── state.ts │ ├── index.ts │ └── use-load-model │ │ ├── file-type-hooks │ │ ├── index.ts │ │ ├── use-load-binary.ts │ │ └── use-load-gltf.ts │ │ ├── utils │ │ ├── index.ts │ │ ├── array-buffer-to-base64.ts │ │ └── read-directory.ts │ │ ├── loaders │ │ ├── index.ts │ │ ├── create-usdz-loader.ts │ │ └── create-gltf-loader.ts │ │ ├── index.ts │ │ ├── model-context.tsx │ │ ├── event-system.ts │ │ ├── state.ts │ │ └── types.ts │ ├── .babelrc │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── .eslintrc.json │ ├── project.json │ ├── package.json │ └── vite.config.ts ├── jest.preset.js ├── .vscode └── extensions.json ├── .prettierignore ├── jest.config.ts ├── .gitignore ├── .github ├── workflows │ ├── lint-build.yaml │ ├── version-release.yaml │ ├── chromatic-vctrl-viewer.yaml │ └── deploy-official-website.yaml └── dependabot.yml ├── .eslintrc.json ├── tsconfig.base.json ├── nx.json ├── CONTRIBUTING.md └── package.json /.npmrc: -------------------------------------------------------------------------------- 1 | git-urlrewrite=false -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /apps/official-website/.gitignore: -------------------------------------------------------------------------------- 1 | dev-dist 2 | .env -------------------------------------------------------------------------------- /shared/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components'; 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | draco 3 | public 4 | assets -------------------------------------------------------------------------------- /apps/official-website/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / -------------------------------------------------------------------------------- /apps/official-website/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/official-website/src/pages/editor/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './editor'; 2 | -------------------------------------------------------------------------------- /apps/official-website/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | draco 3 | public 4 | assets 5 | dev-dist -------------------------------------------------------------------------------- /packages/viewer/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as VectrealViewer } from './vectreal-viewer'; 2 | -------------------------------------------------------------------------------- /packages/hooks/src/use-export-model/index.ts: -------------------------------------------------------------------------------- 1 | export { default as useExportModel } from './use-export-model'; 2 | -------------------------------------------------------------------------------- /packages/viewer/src/components/assets/types.ts: -------------------------------------------------------------------------------- 1 | export interface IconProps { 2 | className?: string; 3 | } 4 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nx/jest/preset').default; 2 | 3 | module.exports = { ...nxPreset }; 4 | -------------------------------------------------------------------------------- /packages/hooks/src/use-optimize-model/index.ts: -------------------------------------------------------------------------------- 1 | export { default as useOptimizeModel } from './use-optimize-model'; 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["esbenp.prettier-vscode", "firsttris.vscode-jest-runner"] 3 | } 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | /dist 3 | /coverage 4 | /.nx/cache 5 | /.nx/workspace-data -------------------------------------------------------------------------------- /apps/official-website/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/favicon.ico -------------------------------------------------------------------------------- /packages/hooks/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-load-model'; 2 | export * from './use-optimize-model'; 3 | export * from './use-export-model'; 4 | -------------------------------------------------------------------------------- /apps/official-website/public/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/mstile-70x70.png -------------------------------------------------------------------------------- /apps/official-website/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/favicon-16x16.png -------------------------------------------------------------------------------- /apps/official-website/public/favicon-194x194.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/favicon-194x194.png -------------------------------------------------------------------------------- /apps/official-website/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/favicon-32x32.png -------------------------------------------------------------------------------- /apps/official-website/public/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/mstile-144x144.png -------------------------------------------------------------------------------- /apps/official-website/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/mstile-150x150.png -------------------------------------------------------------------------------- /apps/official-website/public/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/mstile-310x150.png -------------------------------------------------------------------------------- /apps/official-website/public/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/mstile-310x310.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon.png -------------------------------------------------------------------------------- /apps/official-website/public/assets/vans-shoe.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/assets/vans-shoe.glb -------------------------------------------------------------------------------- /apps/official-website/public/screenshot-mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/screenshot-mobile.png -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import { getJestProjectsAsync } from '@nx/jest'; 2 | 3 | export default async () => ({ 4 | projects: await getJestProjectsAsync(), 5 | }); 6 | -------------------------------------------------------------------------------- /apps/official-website/public/assets/DamagedHelmet.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/assets/DamagedHelmet.glb -------------------------------------------------------------------------------- /apps/official-website/public/draco/draco_decoder.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/draco/draco_decoder.wasm -------------------------------------------------------------------------------- /apps/official-website/public/screenshot-desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/screenshot-desktop.png -------------------------------------------------------------------------------- /apps/official-website/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /apps/official-website/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /apps/official-website/src/components/assets/react-graphic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/src/components/assets/react-graphic.png -------------------------------------------------------------------------------- /packages/hooks/src/use-load-model/file-type-hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { default as useLoadGltf } from './use-load-gltf'; 2 | export { default as useLoadBinary } from './use-load-binary'; 3 | -------------------------------------------------------------------------------- /packages/hooks/src/use-export-model/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { default as dataURItoBlob } from './data-uri-to-blob'; 2 | export * from './export-handlers'; 3 | export * from './file-helpers'; 4 | -------------------------------------------------------------------------------- /packages/hooks/src/use-load-model/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { default as arrayBufferToBase64 } from './array-buffer-to-base64'; 2 | export { default as readDirectory } from './read-directory'; 3 | -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-57x57-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-57x57-precomposed.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-60x60-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-60x60-precomposed.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-72x72-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-72x72-precomposed.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-76x76-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-76x76-precomposed.png -------------------------------------------------------------------------------- /packages/hooks/src/use-load-model/loaders/index.ts: -------------------------------------------------------------------------------- 1 | export { default as createGltfLoader } from './create-gltf-loader'; 2 | export { default as createUsdzLoader } from './create-usdz-loader'; 3 | -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-114x114-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-114x114-precomposed.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-120x120-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-120x120-precomposed.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-144x144-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-144x144-precomposed.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-152x152-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-152x152-precomposed.png -------------------------------------------------------------------------------- /apps/official-website/public/apple-touch-icon-180x180-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Vectreal/vectreal-platform/HEAD/apps/official-website/public/apple-touch-icon-180x180-precomposed.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | .nx/ 4 | vite.config.mts.timestamp-* 5 | vite.config.ts.timestamp-* 6 | .DS_Store 7 | **/vite.config.{js,ts,mjs,mts,cjs,cts}.timestamp* 8 | storybook-static 9 | *.log -------------------------------------------------------------------------------- /packages/hooks/src/use-load-model/index.ts: -------------------------------------------------------------------------------- 1 | export { default as useLoadModel } from './use-load-model'; 2 | export { type ModelFile, ModelFileTypes } from './types'; 3 | export * from './model-context'; 4 | -------------------------------------------------------------------------------- /shared/README.md: -------------------------------------------------------------------------------- 1 | # shared 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test shared` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /shared/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /shared/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@nx/react/babel", 5 | { 6 | "runtime": "automatic", 7 | "useBuiltIns": "usage" 8 | } 9 | ] 10 | ], 11 | "plugins": [] 12 | } 13 | -------------------------------------------------------------------------------- /packages/viewer/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { default as SpinnerWrapper } from './spinner-wrapper'; 2 | export { 3 | default as InfoPopover, 4 | type InfoPopoverProps, 5 | defaultInfoPopoverProps, 6 | } from './info-popover'; 7 | -------------------------------------------------------------------------------- /apps/official-website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vctrl/official-website", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "keywords": [], 7 | "author": "", 8 | "license": "ISC" 9 | } 10 | -------------------------------------------------------------------------------- /packages/hooks/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@nx/react/babel", 5 | { 6 | "runtime": "automatic", 7 | "useBuiltIns": "usage" 8 | } 9 | ] 10 | ], 11 | "plugins": [] 12 | } 13 | -------------------------------------------------------------------------------- /packages/viewer/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@nx/react/babel", 5 | { 6 | "runtime": "automatic", 7 | "useBuiltIns": "usage" 8 | } 9 | ] 10 | ], 11 | "plugins": [] 12 | } 13 | -------------------------------------------------------------------------------- /apps/official-website/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vctrl/official-website", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/official-website/src", 5 | "projectType": "application", 6 | "tags": [] 7 | } 8 | -------------------------------------------------------------------------------- /apps/official-website/src/components/providers/index.ts: -------------------------------------------------------------------------------- 1 | export { default as EditorProvider, useEditorContext } from './editor-provider'; 2 | export { default as ThemeProvider, useTheme } from './theme-provider'; 3 | export { default as RouterProvider } from './router-provider'; 4 | -------------------------------------------------------------------------------- /apps/official-website/src/lib/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { default as useAcceptPattern } from './use-accept-pattern'; 2 | export { default as useInitGA } from './use-init-ga'; 3 | export { default as useIsMobile } from './use-is-mobile'; 4 | export { default as useMedia } from './use-media'; 5 | -------------------------------------------------------------------------------- /shared/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shared", 3 | "$schema": "../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "shared/src", 5 | "projectType": "library", 6 | "tags": [], 7 | "// targets": "to see all targets run: nx show project shared --web", 8 | "targets": {} 9 | } 10 | -------------------------------------------------------------------------------- /apps/official-website/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 8080; 3 | 4 | add_header Cross-Origin-Resource-Policy cross-origin; 5 | 6 | location / { 7 | root /usr/share/nginx/html; 8 | index index.html index.htm; 9 | try_files $uri $uri/ /index.html; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /apps/official-website/src/app.tsx: -------------------------------------------------------------------------------- 1 | import { RouterProvider, ThemeProvider } from './components/providers'; 2 | 3 | import './globals.css'; 4 | 5 | const App = () => { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | }; 12 | 13 | export default App; 14 | -------------------------------------------------------------------------------- /packages/viewer/src/components/spinner-wrapper.tsx: -------------------------------------------------------------------------------- 1 | import styles from '../styles.module.css'; 2 | 3 | interface Props { 4 | loader: JSX.Element; 5 | } 6 | 7 | const SpinnerWrapper = ({ loader }: Props) => { 8 | return
{loader}
; 9 | }; 10 | 11 | export default SpinnerWrapper; 12 | -------------------------------------------------------------------------------- /packages/viewer/.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | // Replace your-renderer with the renderer you are using (e.g., react, vue3) 2 | import type { Preview } from '@storybook/react'; 3 | 4 | const preview: Preview = { 5 | // ...rest of preview 6 | //👇 Enables auto-generated documentation for all stories 7 | tags: ['autodocs'], 8 | }; 9 | 10 | export default preview; 11 | -------------------------------------------------------------------------------- /shared/src/components/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "../lib/utils" 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) { 7 | return ( 8 |
12 | ) 13 | } 14 | 15 | export { Skeleton } 16 | -------------------------------------------------------------------------------- /apps/official-website/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | 4 | import App from './app'; 5 | 6 | const container = document.getElementById('root') as HTMLElement; 7 | const root = ReactDOM.createRoot(container); 8 | 9 | root.render( 10 | 11 | 12 | , 13 | ); 14 | -------------------------------------------------------------------------------- /apps/official-website/src/pages/editor/loading-overlay.tsx: -------------------------------------------------------------------------------- 1 | import { DefaultSpinner } from '@vctrl/shared/components'; 2 | 3 | const LoadingOverlay = () => { 4 | return ( 5 |
6 | 7 |
8 | ); 9 | }; 10 | 11 | export default LoadingOverlay; 12 | -------------------------------------------------------------------------------- /shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react-jsx", 4 | "allowJs": false, 5 | "esModuleInterop": false, 6 | "allowSyntheticDefaultImports": true, 7 | "strict": true 8 | }, 9 | "files": [], 10 | "include": [], 11 | "references": [ 12 | { 13 | "path": "./tsconfig.lib.json" 14 | } 15 | ], 16 | "extends": "../tsconfig.base.json" 17 | } 18 | -------------------------------------------------------------------------------- /shared/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@nx/react", "../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/official-website/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@nx/react", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/official-website/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'official-website', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', 7 | '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], 8 | }, 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 10 | coverageDirectory: '../../coverage/apps/official-website', 11 | }; 12 | -------------------------------------------------------------------------------- /packages/hooks/src/use-load-model/loaders/create-usdz-loader.ts: -------------------------------------------------------------------------------- 1 | import { USDZLoader } from 'three/examples/jsm/loaders/USDZLoader'; 2 | 3 | import eventSystem from '../event-system'; 4 | 5 | function createUsdzLoader() { 6 | const usdzLoader = new USDZLoader(); 7 | 8 | usdzLoader.manager.onError = (url) => { 9 | eventSystem.emit('load-error', `Failed to load file ${url}`); 10 | }; 11 | 12 | return usdzLoader; 13 | } 14 | 15 | export default createUsdzLoader; 16 | -------------------------------------------------------------------------------- /apps/official-website/src/components/typography/typography-muted.tsx: -------------------------------------------------------------------------------- 1 | import { PropsWithChildren } from 'react'; 2 | 3 | import { cn } from '@vctrl/shared/lib/utils'; 4 | 5 | interface Props extends PropsWithChildren { 6 | className?: string; 7 | } 8 | export function TypographyMuted({ children, className }: Props) { 9 | return ( 10 |

{children}

11 | ); 12 | } 13 | 14 | export default TypographyMuted; 15 | -------------------------------------------------------------------------------- /apps/official-website/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | #9f00a7 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/hooks/src/use-export-model/types.ts: -------------------------------------------------------------------------------- 1 | export interface URIBufferObject { 2 | uri: string; 3 | byteLength: number; 4 | } 5 | 6 | export interface TexturesObject { 7 | name: string; 8 | sampler: number; 9 | source: number; 10 | } 11 | 12 | export interface ImageDataObject { 13 | data?: Uint8Array | ArrayBuffer; 14 | uri?: string; 15 | mimeType?: string; 16 | } 17 | 18 | export interface ExportResult { 19 | buffers?: ArrayBuffer[] | URIBufferObject[]; 20 | images?: ImageDataObject[]; 21 | textures?: TexturesObject[]; 22 | } 23 | -------------------------------------------------------------------------------- /packages/hooks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react-jsx", 4 | "lib": ["ESNext", "DOM", "DOM.Iterable", "DOM.AsyncIterable"], 5 | "allowJs": false, 6 | "esModuleInterop": false, 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true, 9 | "isolatedModules": true, 10 | "noEmit": true, 11 | "types": ["vite/client"] 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | } 19 | ], 20 | "extends": "../../tsconfig.base.json" 21 | } 22 | -------------------------------------------------------------------------------- /apps/official-website/src/components/modal-close-button.tsx: -------------------------------------------------------------------------------- 1 | import { Cross2Icon } from '@radix-ui/react-icons'; 2 | import { Button, ButtonProps } from '@vctrl/shared/components'; 3 | 4 | const CloseButton = ({ 5 | onClick, 6 | title, 7 | }: Pick) => ( 8 | 17 | ); 18 | 19 | export default CloseButton; 20 | -------------------------------------------------------------------------------- /packages/viewer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react-jsx", 4 | "allowJs": false, 5 | "esModuleInterop": false, 6 | "allowSyntheticDefaultImports": true, 7 | "strict": true, 8 | "lib": ["ESNext", "DOM", "DOM.Iterable", "DOM.AsyncIterable"], 9 | "types": ["vite/client"] 10 | }, 11 | "files": [], 12 | "include": [], 13 | "references": [ 14 | { 15 | "path": "./tsconfig.lib.json" 16 | }, 17 | { 18 | "path": "./tsconfig.storybook.json" 19 | } 20 | ], 21 | "extends": "../../tsconfig.base.json" 22 | } 23 | -------------------------------------------------------------------------------- /apps/official-website/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react-jsx", 4 | "allowJs": false, 5 | "esModuleInterop": false, 6 | "allowSyntheticDefaultImports": true, 7 | "strict": true, 8 | "lib": ["ESNext", "DOM", "DOM.Iterable", "DOM.AsyncIterable"], 9 | "types": ["vite/client", "node"], 10 | }, 11 | "files": [], 12 | "include": [], 13 | "references": [ 14 | { 15 | "path": "./tsconfig.app.json" 16 | }, 17 | { 18 | "path": "./tsconfig.spec.json" 19 | } 20 | ], 21 | "extends": "../../tsconfig.base.json" 22 | } 23 | -------------------------------------------------------------------------------- /packages/viewer/src/components/scene/index.ts: -------------------------------------------------------------------------------- 1 | export { default as SceneModel } from './scene-model'; 2 | export { 3 | default as SceneCamera, 4 | type CameraProps, 5 | defaultCameraOptions, 6 | } from './scene-camera'; 7 | export { 8 | default as SceneControls, 9 | type ControlsProps, 10 | defaultControlsOptions, 11 | } from './scene-controls'; 12 | export { 13 | default as SceneGrid, 14 | type GridProps, 15 | defaultGridOptions, 16 | } from './scene-grid'; 17 | export { 18 | default as SceneEnvironment, 19 | type EnvProps, 20 | defaultEnvOptions, 21 | } from './scene-environment'; 22 | -------------------------------------------------------------------------------- /apps/official-website/src/components/typography/typography-lead.tsx: -------------------------------------------------------------------------------- 1 | import { PropsWithChildren } from "react"; 2 | 3 | interface Props extends PropsWithChildren { 4 | isHighlighted?: boolean; 5 | } 6 | 7 | export function TypographyLead({ children, isHighlighted }: Props) { 8 | const isHighlightedClass = isHighlighted 9 | ? "text-primary" 10 | : "text-muted-foreground"; 11 | 12 | return ( 13 |

16 | {children} 17 |

18 | ); 19 | } 20 | 21 | export default TypographyLead; 22 | -------------------------------------------------------------------------------- /apps/official-website/src/lib/hooks/use-is-mobile.ts: -------------------------------------------------------------------------------- 1 | import { useMedia } from '.'; 2 | 3 | /** 4 | * Returns true if the user is using a mobile device, determined by the 5 | * presence of a mobile user agent or if the screen width is less than 6 | * 768px. 7 | * 8 | * @returns {boolean} Whether the user is using a mobile device. 9 | */ 10 | const useIsMobile = (): boolean => { 11 | const isMobileSize = useMedia('(max-width: 768px)'); 12 | 13 | return ( 14 | /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent) || 15 | isMobileSize 16 | ); 17 | }; 18 | 19 | export default useIsMobile; 20 | -------------------------------------------------------------------------------- /shared/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc", 5 | "types": [ 6 | "node", 7 | 8 | "@nx/react/typings/cssmodule.d.ts", 9 | "@nx/react/typings/image.d.ts" 10 | ] 11 | }, 12 | "exclude": [ 13 | "jest.config.ts", 14 | "src/**/*.spec.ts", 15 | "src/**/*.test.ts", 16 | "src/**/*.spec.tsx", 17 | "src/**/*.test.tsx", 18 | "src/**/*.spec.js", 19 | "src/**/*.test.js", 20 | "src/**/*.spec.jsx", 21 | "src/**/*.test.jsx" 22 | ], 23 | "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"] 24 | } 25 | -------------------------------------------------------------------------------- /apps/official-website/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": [ 7 | "jest", 8 | "node", 9 | "@nx/react/typings/cssmodule.d.ts", 10 | "@nx/react/typings/image.d.ts" 11 | ] 12 | }, 13 | "include": [ 14 | "jest.config.ts", 15 | "src/**/*.test.ts", 16 | "src/**/*.spec.ts", 17 | "src/**/*.test.tsx", 18 | "src/**/*.spec.tsx", 19 | "src/**/*.test.js", 20 | "src/**/*.spec.js", 21 | "src/**/*.test.jsx", 22 | "src/**/*.spec.jsx", 23 | "src/**/*.d.ts" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /apps/official-website/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": [ 6 | "node", 7 | "@nx/react/typings/cssmodule.d.ts", 8 | "@nx/react/typings/image.d.ts", 9 | "vite/client" 10 | ] 11 | }, 12 | "exclude": [ 13 | "src/**/*.spec.ts", 14 | "src/**/*.test.ts", 15 | "src/**/*.spec.tsx", 16 | "src/**/*.test.tsx", 17 | "src/**/*.spec.js", 18 | "src/**/*.test.js", 19 | "src/**/*.spec.jsx", 20 | "src/**/*.test.jsx" 21 | ], 22 | "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"] 23 | } 24 | -------------------------------------------------------------------------------- /packages/hooks/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true, 5 | "isolatedModules": true, 6 | "declaration": true, 7 | "types": [ 8 | "node", 9 | "@nx/react/typings/cssmodule.d.ts", 10 | "@nx/react/typings/image.d.ts", 11 | "vite/client" 12 | ] 13 | }, 14 | "exclude": [ 15 | "**/*.spec.ts", 16 | "**/*.test.ts", 17 | "**/*.spec.tsx", 18 | "**/*.test.tsx", 19 | "**/*.spec.js", 20 | "**/*.test.js", 21 | "**/*.spec.jsx", 22 | "**/*.test.jsx" 23 | ], 24 | "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"] 25 | } 26 | -------------------------------------------------------------------------------- /packages/hooks/src/use-export-model/utils/data-uri-to-blob.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Converts a data URI to a Blob. 3 | * 4 | * @param {string} dataURI - The data URI to convert. 5 | * 6 | * @returns {Blob} The Blob object. 7 | */ 8 | const dataURItoBlob = (dataURI: string): Blob => { 9 | const byteString = atob(dataURI.split(',')[1]); 10 | const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; 11 | 12 | const ab = new ArrayBuffer(byteString.length); 13 | const ia = new Uint8Array(ab); 14 | 15 | for (let i = 0; i < byteString.length; i++) { 16 | ia[i] = byteString.charCodeAt(i); 17 | } 18 | 19 | return new Blob([ab], { type: mimeString }); 20 | }; 21 | 22 | export default dataURItoBlob; 23 | -------------------------------------------------------------------------------- /packages/viewer/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": [ 6 | "node", 7 | "@nx/react/typings/cssmodule.d.ts", 8 | "@nx/react/typings/image.d.ts", 9 | "vite/client" 10 | ] 11 | }, 12 | "exclude": [ 13 | "**/*.spec.ts", 14 | "**/*.test.ts", 15 | "**/*.spec.tsx", 16 | "**/*.test.tsx", 17 | "**/*.spec.js", 18 | "**/*.test.js", 19 | "**/*.spec.jsx", 20 | "**/*.test.jsx", 21 | "**/*.stories.ts", 22 | "**/*.stories.js", 23 | "**/*.stories.jsx", 24 | "**/*.stories.tsx" 25 | ], 26 | "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"] 27 | } 28 | -------------------------------------------------------------------------------- /packages/viewer/src/components/assets/vectreal-logo.tsx: -------------------------------------------------------------------------------- 1 | import { IconProps } from './types'; 2 | 3 | const VectrealLogo = ({ className }: IconProps) => { 4 | return ( 5 | 6 | 7 | 11 | 12 | 13 | ); 14 | }; 15 | 16 | export default VectrealLogo; 17 | -------------------------------------------------------------------------------- /shared/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './accordion'; 2 | export * from './avatar'; 3 | export * from './background-beams'; 4 | export * from './badge'; 5 | export * from './button'; 6 | export * from './card'; 7 | export * from './default-spinner'; 8 | export * from './dialog'; 9 | export * from './dropdown-menu'; 10 | export * from './glowing-stars'; 11 | export * from './hero-highlight'; 12 | export * from './input'; 13 | export * from './label'; 14 | export * from './menubar'; 15 | export * from './navigation-menu'; 16 | export * from './popover'; 17 | export * from './progress'; 18 | export * from './sheet'; 19 | export * from './skeleton'; 20 | export * from './sonner'; 21 | export * from './textarea'; 22 | export * from './tooltip'; 23 | export * from './typewriter-effect'; 24 | -------------------------------------------------------------------------------- /apps/official-website/src/components/assets/google-icon.tsx: -------------------------------------------------------------------------------- 1 | interface GoogleIconProps { 2 | className?: string; 3 | } 4 | 5 | const GoogleLogoIcon = ({ className }: GoogleIconProps) => { 6 | return ( 7 | 16 | 17 | 18 | ); 19 | }; 20 | 21 | export default GoogleLogoIcon; -------------------------------------------------------------------------------- /packages/hooks/src/use-load-model/utils/array-buffer-to-base64.ts: -------------------------------------------------------------------------------- 1 | // Helper function to convert ArrayBuffer to base64 2 | async function arrayBufferToBase64(arrayBuffer: ArrayBuffer) { 3 | // Create a Blob from the ArrayBuffer 4 | const blob = new Blob([arrayBuffer]); 5 | 6 | // Use the FileReader to convert the Blob to a Base64 string 7 | const reader = new FileReader(); 8 | return new Promise((resolve, reject) => { 9 | reader.onloadend = () => { 10 | if (!reader?.result) return; 11 | // Extract the Base64 string from the data URL 12 | const base64String = (reader?.result as string).split(',')[1]; 13 | resolve(base64String); 14 | }; 15 | reader.onerror = reject; 16 | reader.readAsDataURL(blob); 17 | }); 18 | } 19 | 20 | export default arrayBufferToBase64; 21 | -------------------------------------------------------------------------------- /apps/official-website/src/components/title-section.tsx: -------------------------------------------------------------------------------- 1 | import { PropsWithChildren } from 'react'; 2 | 3 | import { BackgroundBeams } from '@vctrl/shared/components'; 4 | 5 | import { useIsMobile } from '../lib/hooks'; 6 | 7 | interface TitleSectionProps extends PropsWithChildren { 8 | className?: string; 9 | heading: string; 10 | } 11 | 12 | const TitleSection = ({ children, heading, className }: TitleSectionProps) => { 13 | const isMobile = useIsMobile(); 14 | 15 | return ( 16 |
17 | {!isMobile && } 18 |

{heading}

19 | {children} 20 |
21 | ); 22 | }; 23 | 24 | export default TitleSection; 25 | -------------------------------------------------------------------------------- /shared/src/components/default-spinner.tsx: -------------------------------------------------------------------------------- 1 | export const DefaultSpinner = () => { 2 | return ( 3 | 9 | 13 | 14 | 21 | 22 | 23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /shared/src/components/label.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import * as LabelPrimitive from "@radix-ui/react-label" 3 | import { cva, type VariantProps } from "class-variance-authority" 4 | 5 | import { cn } from "../lib/utils" 6 | 7 | const labelVariants = cva( 8 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 9 | ) 10 | 11 | const Label = React.forwardRef< 12 | React.ElementRef, 13 | React.ComponentPropsWithoutRef & 14 | VariantProps 15 | >(({ className, ...props }, ref) => ( 16 | 21 | )) 22 | Label.displayName = LabelPrimitive.Root.displayName 23 | 24 | export { Label } 25 | -------------------------------------------------------------------------------- /.github/workflows/lint-build.yaml: -------------------------------------------------------------------------------- 1 | name: Lint and build affected NX projects 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize, reopened] 6 | 7 | jobs: 8 | lint-build: 9 | runs-on: ubuntu-22.04 10 | strategy: 11 | matrix: 12 | node-version: [22] 13 | steps: 14 | - uses: actions/checkout@v4 15 | with: 16 | fetch-depth: 0 17 | 18 | - name: Use Node.js ${{ matrix.node-version }} 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: ${{ matrix.node-version }} 22 | cache: 'npm' 23 | 24 | - name: Install dependencies 25 | run: npm ci 26 | 27 | - name: Lint 28 | run: npx nx affected --target=lint --base=origin/${{ github.event.pull_request.base.ref }} --head=origin/${{ github.event.pull_request.head.ref }} 29 | -------------------------------------------------------------------------------- /apps/official-website/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage 2 | FROM node:20-alpine AS build-stage 3 | 4 | WORKDIR /app 5 | 6 | # Copy only package.json and package-lock.json (or yarn.lock) first 7 | COPY package*.json ./ 8 | 9 | # Install dependencies 10 | RUN npm i 11 | 12 | # Copy the rest of the application code 13 | COPY . . 14 | 15 | # Build the application 16 | RUN npx nx build vctrl/official-website 17 | 18 | # Production stage 19 | FROM nginx:alpine 20 | 21 | # Copy the built app from the previous stage 22 | COPY --from=build-stage /app/dist/apps/official-website /usr/share/nginx/html 23 | 24 | # Remove the default nginx configuration 25 | RUN rm /etc/nginx/conf.d/default.conf 26 | 27 | # Copy the nginx configuration file 28 | COPY ./apps/official-website/nginx.conf /etc/nginx/conf.d 29 | 30 | EXPOSE 80 31 | 32 | CMD ["nginx", "-g", "daemon off;"] -------------------------------------------------------------------------------- /shared/src/components/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { cn } from '../lib/utils'; 4 | 5 | export type TextareaProps = React.TextareaHTMLAttributes; 6 | 7 | const Textarea = React.forwardRef( 8 | ({ className, ...props }, ref) => { 9 | return ( 10 |