From ba8e1f5e6cfbdc3071a27707a9c99c39c74ca6bc Mon Sep 17 00:00:00 2001 From: Bela Bohlender Date: Mon, 26 Feb 2024 18:53:18 +0100 Subject: [PATCH] feat: image src can be texture added: market example --- examples/dashboard/vite.config.ts | 2 - examples/lucide/vite.config.ts | 2 - examples/market/index.html | 13 ++ examples/market/package.json | 18 +++ examples/market/src/App.tsx | 122 ++++++++++++++++++ .../market/src/components/album-artwork.tsx | 35 +++++ examples/market/src/components/menu.tsx | 39 ++++++ examples/market/src/components/sidebar.tsx | 92 +++++++++++++ examples/market/src/data/albums.ts | 61 +++++++++ examples/market/src/data/playlists.ts | 16 +++ examples/market/src/index.tsx | 10 ++ examples/market/src/styles.css | 0 examples/market/tsconfig.json | 8 ++ examples/market/vite.config.ts | 14 ++ examples/uikit/package.json | 3 + examples/uikit/src/App.tsx | 33 +++-- examples/uikit/vite.config.ts | 2 - .../default/{menu-bar.tsx => menubar.tsx} | 95 ++++++-------- packages/kits/default/package.json | 5 +- packages/uikit/src/components/image.tsx | 15 ++- packages/uikit/src/components/input.tsx | 3 +- packages/uikit/src/components/root.tsx | 4 +- packages/uikit/src/flex/node.ts | 7 +- packages/uikit/src/index.ts | 2 +- pnpm-lock.yaml | 37 ++++++ 25 files changed, 553 insertions(+), 85 deletions(-) create mode 100644 examples/market/index.html create mode 100644 examples/market/package.json create mode 100644 examples/market/src/App.tsx create mode 100644 examples/market/src/components/album-artwork.tsx create mode 100644 examples/market/src/components/menu.tsx create mode 100644 examples/market/src/components/sidebar.tsx create mode 100644 examples/market/src/data/albums.ts create mode 100644 examples/market/src/data/playlists.ts create mode 100644 examples/market/src/index.tsx create mode 100644 examples/market/src/styles.css create mode 100644 examples/market/tsconfig.json create mode 100644 examples/market/vite.config.ts rename packages/kits/default/{menu-bar.tsx => menubar.tsx} (80%) diff --git a/examples/dashboard/vite.config.ts b/examples/dashboard/vite.config.ts index dc9fef9d..9a823cca 100644 --- a/examples/dashboard/vite.config.ts +++ b/examples/dashboard/vite.config.ts @@ -2,8 +2,6 @@ import { defineConfig } from 'vite' import path from 'path' import react from '@vitejs/plugin-react' -console.log(path.resolve(__dirname, '../../packages/uikit')) - // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], diff --git a/examples/lucide/vite.config.ts b/examples/lucide/vite.config.ts index dc9fef9d..9a823cca 100644 --- a/examples/lucide/vite.config.ts +++ b/examples/lucide/vite.config.ts @@ -2,8 +2,6 @@ import { defineConfig } from 'vite' import path from 'path' import react from '@vitejs/plugin-react' -console.log(path.resolve(__dirname, '../../packages/uikit')) - // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], diff --git a/examples/market/index.html b/examples/market/index.html new file mode 100644 index 00000000..cf853ae4 --- /dev/null +++ b/examples/market/index.html @@ -0,0 +1,13 @@ + + + + + + + Document + + + +
+ + diff --git a/examples/market/package.json b/examples/market/package.json new file mode 100644 index 00000000..8df37172 --- /dev/null +++ b/examples/market/package.json @@ -0,0 +1,18 @@ +{ + "type": "module", + "dependencies": { + "@react-three/drei": "^9.96.1", + "@react-three/fiber": "^8.15.13", + "@react-three/postprocessing": "^2.16.0", + "@react-three/uikit": "workspace:^", + "@react-three/uikit-lucide": "workspace:^", + "@types/three": "^0.160.0", + "r3f-perf": "^7.1.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "three": "^0.160.0" + }, + "scripts": { + "dev": "vite --host" + } +} diff --git a/examples/market/src/App.tsx b/examples/market/src/App.tsx new file mode 100644 index 00000000..820e21a3 --- /dev/null +++ b/examples/market/src/App.tsx @@ -0,0 +1,122 @@ +import { Environment, OrbitControls } from '@react-three/drei' +import { Canvas } from '@react-three/fiber' +import { EffectComposer, TiltShift2 } from '@react-three/postprocessing' +import { Root, Container, Image, Text, Fullscreen, DefaultProperties } from '@react-three/uikit' +import { PlusCircle } from '@react-three/uikit-lucide' +import { DefaultColors, colors } from '@/defaults.js' +import { DialogAnchor } from '@/dialog.js' +import { Tabs, TabsList, TabsContent, TabsTrigger } from '@/tabs.js' +import { Separator } from '@/separator.js' +import { Button } from '@/button.js' +import { AlbumArtwork } from './components/album-artwork' +import { listenNowAlbums, madeForYouAlbums } from './data/albums' +import { Sidebar } from './components/sidebar' +import { playlists } from './data/playlists' +import { Menu } from './components/menu' + +export default function App() { + return ( + + {/* + + + + + + + + + + + */} + + + + + + + + + ) +} + +export function MarketPage() { + return ( + + + + + + + + + + + Models + + + HDRIS + + + Materials + + + + + + + + + + + Trending + + + Top picks for you. Updated daily. + + + + + + {listenNowAlbums.map((album) => ( + + ))} + + + + Made By You + + + Your personal models. + + + + + {madeForYouAlbums.map((album) => ( + + ))} + + + + + + + ) +} diff --git a/examples/market/src/components/album-artwork.tsx b/examples/market/src/components/album-artwork.tsx new file mode 100644 index 00000000..7f95aecc --- /dev/null +++ b/examples/market/src/components/album-artwork.tsx @@ -0,0 +1,35 @@ +import { Container, Text, Image } from '@react-three/uikit' +import { Album } from '../data/albums.js' +import { ComponentPropsWithoutRef } from 'react' +import { colors } from '@/defaults.js' + +export function AlbumArtwork({ + album, + aspectRatio = 'portrait', + width, + height, + ...props +}: { + album: Album + aspectRatio?: 'portrait' | 'square' +} & Omit, 'aspectRatio'>) { + return ( + + + + + {album.name} + + + {album.artist} + + + + ) +} diff --git a/examples/market/src/components/menu.tsx b/examples/market/src/components/menu.tsx new file mode 100644 index 00000000..3c7719d8 --- /dev/null +++ b/examples/market/src/components/menu.tsx @@ -0,0 +1,39 @@ +import { Menubar, MenubarMenu, MenubarTrigger } from '@/menubar.js' +import { SvgIconFromText, Text } from '@react-three/uikit' + +export function Menu() { + return ( + + + + + + + + + File + + + + + Edit + + + + + View + + + + + Account + + + + ) +} diff --git a/examples/market/src/components/sidebar.tsx b/examples/market/src/components/sidebar.tsx new file mode 100644 index 00000000..c08c6ae2 --- /dev/null +++ b/examples/market/src/components/sidebar.tsx @@ -0,0 +1,92 @@ +import { Container, Text } from '@react-three/uikit' +import { Button } from '@/button.js' +import { Playlist } from '../data/playlists.js' +import { ComponentPropsWithoutRef } from 'react' +import { Eclipse, Package, Star, User, Image as ImageIcon } from '@react-three/uikit-lucide' + +export function Sidebar({ + playlists, + ...props +}: ComponentPropsWithoutRef & { + playlists: Playlist[] +}) { + return ( + + + + + Discover + + + + + + + + + + Collections + + + + + + + + + + + + Favorits + + + {playlists?.map((playlist, i) => ( + + ))} + + + + + ) +} diff --git a/examples/market/src/data/albums.ts b/examples/market/src/data/albums.ts new file mode 100644 index 00000000..b9ab3613 --- /dev/null +++ b/examples/market/src/data/albums.ts @@ -0,0 +1,61 @@ +export interface Album { + name: string + artist: string + cover: string +} + +export const listenNowAlbums: Album[] = [ + { + name: 'React Rendezvous', + artist: 'Ethan Byte', + cover: 'https://images.unsplash.com/photo-1611348586804-61bf6c080437?w=300&dpr=2&q=80', + }, + { + name: 'Async Awakenings', + artist: 'Nina Netcode', + cover: 'https://images.unsplash.com/photo-1468817814611-b7edf94b5d60?w=300&dpr=2&q=80', + }, + { + name: 'The Art of Reusability', + artist: 'Lena Logic', + cover: 'https://images.unsplash.com/photo-1528143358888-6d3c7f67bd5d?w=300&dpr=2&q=80', + }, + { + name: 'Stateful Symphony', + artist: 'Beth Binary', + cover: 'https://images.unsplash.com/photo-1490300472339-79e4adc6be4a?w=300&dpr=2&q=80', + }, +] + +export const madeForYouAlbums: Album[] = [ + { + name: 'Thinking Components', + artist: 'Lena Logic', + cover: 'https://images.unsplash.com/photo-1615247001958-f4bc92fa6a4a?w=300&dpr=2&q=80', + }, + { + name: 'Functional Fury', + artist: 'Beth Binary', + cover: 'https://images.unsplash.com/photo-1513745405825-efaf9a49315f?w=300&dpr=2&q=80', + }, + { + name: 'React Rendezvous', + artist: 'Ethan Byte', + cover: 'https://images.unsplash.com/photo-1614113489855-66422ad300a4?w=300&dpr=2&q=80', + }, + { + name: 'Stateful Symphony', + artist: 'Beth Binary', + cover: 'https://images.unsplash.com/photo-1446185250204-f94591f7d702?w=300&dpr=2&q=80', + }, + { + name: 'Async Awakenings', + artist: 'Nina Netcode', + cover: 'https://images.unsplash.com/photo-1468817814611-b7edf94b5d60?w=300&dpr=2&q=80', + }, + { + name: 'The Art of Reusability', + artist: 'Lena Logic', + cover: 'https://images.unsplash.com/photo-1490300472339-79e4adc6be4a?w=300&dpr=2&q=80', + }, +] diff --git a/examples/market/src/data/playlists.ts b/examples/market/src/data/playlists.ts new file mode 100644 index 00000000..d395ac4c --- /dev/null +++ b/examples/market/src/data/playlists.ts @@ -0,0 +1,16 @@ +export type Playlist = (typeof playlists)[number] + +export const playlists = [ + 'Recently Added', + 'Recently Played', + 'Top Songs', + 'Top Albums', + 'Top Artists', + 'Logic Discography', + 'Bedtime Beats', + 'Feeling Happy', + 'I miss Y2K Pop', + 'Runtober', + 'Mellow Days', + 'Eminem Essentials', +] diff --git a/examples/market/src/index.tsx b/examples/market/src/index.tsx new file mode 100644 index 00000000..da84256b --- /dev/null +++ b/examples/market/src/index.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './styles.css' +import App from './App' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/examples/market/src/styles.css b/examples/market/src/styles.css new file mode 100644 index 00000000..e69de29b diff --git a/examples/market/tsconfig.json b/examples/market/tsconfig.json new file mode 100644 index 00000000..38ab47e6 --- /dev/null +++ b/examples/market/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "paths": { + "@/*": ["../../packages/kits/default/*"] + } + } +} diff --git a/examples/market/vite.config.ts b/examples/market/vite.config.ts new file mode 100644 index 00000000..9a823cca --- /dev/null +++ b/examples/market/vite.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite' +import path from 'path' +import react from '@vitejs/plugin-react' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + resolve: { + alias: [ + { find: '@', replacement: path.resolve(__dirname, '../../packages/kits/default') }, + { find: '@react-three/uikit', replacement: path.resolve(__dirname, '../../packages/uikit/src/index.ts') }, + ], + }, +}) diff --git a/examples/uikit/package.json b/examples/uikit/package.json index 3142e866..44d5ad81 100644 --- a/examples/uikit/package.json +++ b/examples/uikit/package.json @@ -11,5 +11,8 @@ }, "scripts": { "dev": "vite --host" + }, + "devDependencies": { + "@types/three": "^0.160.0" } } diff --git a/examples/uikit/src/App.tsx b/examples/uikit/src/App.tsx index 735248af..883605d3 100644 --- a/examples/uikit/src/App.tsx +++ b/examples/uikit/src/App.tsx @@ -12,8 +12,11 @@ import { Image, Fullscreen, } from '@react-three/uikit' +import { RenderTexture } from '@react-three/drei' +import { Texture } from 'three' export default function App() { + const [texture, setTexture] = useState(null) const [show, setShow] = useState(false) const s = useMemo(() => signal(5), []) const x = useMemo(() => signal('red'), []) @@ -24,6 +27,9 @@ export default function App() { + + + + { t.value += 'X' @@ -50,18 +57,6 @@ export default function App() { > {t} - {show ? ( - - (s.value += 10)} - backgroundColor="yellow" - width={300} - minHeight={300} - height={300} - /> - - - ) : undefined} (x.value = hover ? 'yellow' : undefined)} backgroundColor={x} @@ -96,7 +91,6 @@ export default function App() { Hello world + + {show ? ( + + (s.value += 10)} + backgroundColor="yellow" + width={300} + minHeight={300} + height={300} + /> + + + ) : undefined} ) diff --git a/examples/uikit/vite.config.ts b/examples/uikit/vite.config.ts index dc9fef9d..9a823cca 100644 --- a/examples/uikit/vite.config.ts +++ b/examples/uikit/vite.config.ts @@ -2,8 +2,6 @@ import { defineConfig } from 'vite' import path from 'path' import react from '@vitejs/plugin-react' -console.log(path.resolve(__dirname, '../../packages/uikit')) - // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], diff --git a/packages/kits/default/menu-bar.tsx b/packages/kits/default/menubar.tsx similarity index 80% rename from packages/kits/default/menu-bar.tsx rename to packages/kits/default/menubar.tsx index 30b2c70c..92b37a73 100644 --- a/packages/kits/default/menu-bar.tsx +++ b/packages/kits/default/menubar.tsx @@ -1,13 +1,47 @@ -'use client' +import { Container, DefaultProperties } from '@react-three/uikit' +import { ComponentPropsWithoutRef, ReactNode } from 'react' +import { colors } from './defaults' -import * as React from 'react' -import * as MenubarPrimitive from '@radix-ui/react-menubar' -import { Check, ChevronRight, Circle } from 'lucide-react' - -import { cn } from '@/lib/utils' +export function MenubarMenu({ children }: { children?: ReactNode }) { + return <>{children} +} -const MenubarMenu = MenubarPrimitive.Menu +export function Menubar(props: ComponentPropsWithoutRef) { + return ( + + ) +} +export function MenubarTrigger({ children, ...props }: ComponentPropsWithoutRef) { + //TODO: data-[state=open]:bg-accent data-[state=open]:text-accent-foreground + return ( + + + {children} + + + ) +} +/* const MenubarGroup = MenubarPrimitive.Group const MenubarPortal = MenubarPrimitive.Portal @@ -16,33 +50,6 @@ const MenubarSub = MenubarPrimitive.Sub const MenubarRadioGroup = MenubarPrimitive.RadioGroup -const Menubar = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -Menubar.displayName = MenubarPrimitive.Root.displayName - -const MenubarTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName - const MenubarSubTrigger = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { @@ -188,22 +195,4 @@ const MenubarShortcut = ({ className, ...props }: React.HTMLAttributes } MenubarShortcut.displayname = 'MenubarShortcut' - -export { - Menubar, - MenubarMenu, - MenubarTrigger, - MenubarContent, - MenubarItem, - MenubarSeparator, - MenubarLabel, - MenubarCheckboxItem, - MenubarRadioGroup, - MenubarRadioItem, - MenubarPortal, - MenubarSubContent, - MenubarSubTrigger, - MenubarGroup, - MenubarSub, - MenubarShortcut, -} +*/ diff --git a/packages/kits/default/package.json b/packages/kits/default/package.json index 57d3fda7..d2e676bc 100644 --- a/packages/kits/default/package.json +++ b/packages/kits/default/package.json @@ -1,8 +1,5 @@ { - "scripts": { - "fix:prettier": "prettier --write .", - "fix:eslint": "eslint ./**/*.tsx --fix" - }, + "scripts": {}, "devDependencies": { "@preact/signals-core": "^1.5.1", "@react-three/fiber": "^8.15.13", diff --git a/packages/uikit/src/components/image.tsx b/packages/uikit/src/components/image.tsx index ed9c4854..3daaf972 100644 --- a/packages/uikit/src/components/image.tsx +++ b/packages/uikit/src/components/image.tsx @@ -73,7 +73,7 @@ const materialPropertyTransformation: PropertyTransformation = (key, value, hasP export const Image = forwardRef< ComponentInternals, ImageProperties & { - src: string | Signal + src?: string | Signal | Texture | Signal materialClass?: MaterialClass zIndexOffset?: ZIndexOffset } & EventHandlers & @@ -89,7 +89,8 @@ export const Image = forwardRef< if (tex == null) { return undefined } - return tex.image.width / tex.image.height + const image = tex.source.data as { width: number; height: number } + return image.width / image.height }), [texture], ) @@ -227,9 +228,15 @@ function transformInsideBorder(borderInset: Signal, size: Signal { texture.colorSpace = SRGBColorSpace texture.matrixAutoUpdate = false diff --git a/packages/uikit/src/components/input.tsx b/packages/uikit/src/components/input.tsx index 2e6f6457..5b7f8f40 100644 --- a/packages/uikit/src/components/input.tsx +++ b/packages/uikit/src/components/input.tsx @@ -32,7 +32,7 @@ import { useRootGroupRef, useSignalEffect } from '../utils.js' import { useApplyResponsiveProperties } from '../responsive.js' import { Group } from 'three' import { ElementType, ZIndexOffset, useOrderInfo } from '../order.js' - +/* export type TextProperties = WithConditionals< WithClasses< WithAllAliases> @@ -242,3 +242,4 @@ export function useHtmlInputElement( useEffect(() => () => element.remove(), [element]) return element } +*/ diff --git a/packages/uikit/src/components/root.tsx b/packages/uikit/src/components/root.tsx index f1ec760d..6d0660cc 100644 --- a/packages/uikit/src/components/root.tsx +++ b/packages/uikit/src/components/root.tsx @@ -85,8 +85,8 @@ export const Root = forwardRef< ScrollListeners >((properties, ref) => { const collection = createCollection() - const renderer = useThree((state) => state.gl) - + const renderer = useThree((state) => state.gl) + useEffect(() => patchRenderOrder(renderer), [renderer]) const { sizeX, sizeY } = properties const [precision, pixelSize] = useMemo( diff --git a/packages/uikit/src/flex/node.ts b/packages/uikit/src/flex/node.ts index 35db000b..fbd84e81 100644 --- a/packages/uikit/src/flex/node.ts +++ b/packages/uikit/src/flex/node.ts @@ -259,7 +259,12 @@ export class FlexNode implements WithImmediateProperties { updateVector2Signal(this.scrollable, false, false) } - return [x + Math.max(width, maxContentWidth), y + Math.max(height, maxContentHeight)] + const overflowVisible = this.overflow.value === OVERFLOW_VISIBLE + + return [ + x + Math.max(width, overflowVisible ? maxContentWidth : 0), + y + Math.max(height, overflowVisible ? maxContentHeight : 0), + ] } addLayoutChangeListener(listener: () => void) { diff --git a/packages/uikit/src/index.ts b/packages/uikit/src/index.ts index 50cc4d99..e8fc20ba 100644 --- a/packages/uikit/src/index.ts +++ b/packages/uikit/src/index.ts @@ -7,4 +7,4 @@ export type { LayoutListeners, ViewportListeners } from './components/utils.js' export type { ScrollListeners } from './scroll.js' export type { AllOptionalProperties } from './properties/default.js' export { DefaultProperties } from './properties/default.js' -export * from './components/index.js' \ No newline at end of file +export * from './components/index.js' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d32f319c..ef27d84c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -168,6 +168,39 @@ importers: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) + examples/market: + dependencies: + '@react-three/drei': + specifier: ^9.96.1 + version: 9.96.1(@react-three/fiber@8.15.13)(@types/react@18.2.47)(@types/three@0.160.0)(react-dom@18.2.0)(react@18.2.0)(three@0.160.0) + '@react-three/fiber': + specifier: ^8.15.13 + version: 8.15.13(react-dom@18.2.0)(react@18.2.0)(three@0.160.0) + '@react-three/postprocessing': + specifier: ^2.16.0 + version: 2.16.0(@react-three/fiber@8.15.13)(@types/three@0.160.0)(react@18.2.0)(three@0.160.0) + '@react-three/uikit': + specifier: workspace:^ + version: link:../../packages/uikit + '@react-three/uikit-lucide': + specifier: workspace:^ + version: link:../../packages/icons/lucide + '@types/three': + specifier: ^0.160.0 + version: 0.160.0 + r3f-perf: + specifier: ^7.1.2 + version: 7.1.2(@react-three/fiber@8.15.13)(@types/react@18.2.47)(@types/three@0.160.0)(react-dom@18.2.0)(react@18.2.0)(three@0.160.0) + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + three: + specifier: ^0.160.0 + version: 0.160.0 + examples/uikit: dependencies: '@preact/signals-core': @@ -191,6 +224,10 @@ importers: three: specifier: ^0.160.0 version: 0.160.0 + devDependencies: + '@types/three': + specifier: ^0.160.0 + version: 0.160.0 packages/fonts: dependencies: