mirror of
https://github.com/Afilmory/afilmory
synced 2026-02-01 22:48:17 +00:00
feat: support share to external via iframe
- Added Tailwind CSS plugins and configurations to improve styling across the application. - Introduced new global styles and layout components for better structure and design consistency. - Implemented a MasonryGallery component for responsive photo display. - Enhanced photo item rendering with EXIF data and improved loading states. - Updated package dependencies to include new Tailwind CSS utilities and components. Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
42
apps/ssr/global.d.ts
vendored
Normal file
42
apps/ssr/global.d.ts
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
||||
import type { FC, PropsWithChildren } from 'react'
|
||||
|
||||
declare global {
|
||||
export type NextErrorProps = {
|
||||
reset: () => void
|
||||
error: Error
|
||||
}
|
||||
export type NextPageParams<P extends {}, Props = {}> = PropsWithChildren<
|
||||
{
|
||||
params: Promise<P>
|
||||
searchParams: Promise<Record<string, string | string[] | undefined>>
|
||||
} & Props
|
||||
>
|
||||
|
||||
export type NextPageExtractedParams<
|
||||
P extends {},
|
||||
Props = {},
|
||||
> = PropsWithChildren<
|
||||
{
|
||||
params: P
|
||||
searchParams: Promise<Record<string, string | string[] | undefined>>
|
||||
} & Props
|
||||
>
|
||||
|
||||
export type Component<P = {}> = FC<ComponentType & P>
|
||||
|
||||
export type ComponentType<P = {}> = {
|
||||
className?: string
|
||||
} & PropsWithChildren &
|
||||
P
|
||||
}
|
||||
|
||||
declare module 'react' {
|
||||
export interface AriaAttributes {
|
||||
'data-hide-print'?: boolean
|
||||
'data-event'?: string
|
||||
'data-testid'?: string
|
||||
}
|
||||
}
|
||||
|
||||
export {}
|
||||
@@ -19,17 +19,32 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@afilmory/components": "workspace:*",
|
||||
"@afilmory/data": "workspace:*",
|
||||
"@t3-oss/env-nextjs": "0.13.8",
|
||||
"clsx": "2.1.1",
|
||||
"drizzle-orm": "0.44.2",
|
||||
"es-toolkit": "1.39.5",
|
||||
"linkedom": "0.18.11",
|
||||
"pg": "8.16.2",
|
||||
"postgres": "3.4.7",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react-masonry": "1.0.7",
|
||||
"react-photo-view": "1.2.7",
|
||||
"react-responsive-masonry": "2.7.1",
|
||||
"react-use": "17.6.0",
|
||||
"tailwind-merge": "3.3.1",
|
||||
"tailwind-variants": "catalog:",
|
||||
"thumbhash": "0.1.1",
|
||||
"usehooks-ts": "3.1.1",
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@egoist/tailwindcss-icons": "catalog:",
|
||||
"@iconify-json/mingcute": "catalog:",
|
||||
"@tailwindcss/postcss": "catalog:",
|
||||
"@tailwindcss/typography": "catalog:",
|
||||
"@types/node": "24.0.4",
|
||||
"@types/pg": "8.15.4",
|
||||
"@types/react": "19.1.8",
|
||||
@@ -38,6 +53,12 @@
|
||||
"cross-env": "7.0.3",
|
||||
"dotenv-expand": "catalog:",
|
||||
"drizzle-kit": "0.31.2",
|
||||
"next": "15.3.4"
|
||||
"next": "15.3.4",
|
||||
"postcss": "8.5.6",
|
||||
"tailwind-scrollbar": "catalog:",
|
||||
"tailwindcss": "catalog:",
|
||||
"tailwindcss-animate": "catalog:",
|
||||
"tailwindcss-safe-area": "catalog:",
|
||||
"tailwindcss-uikit-colors": "catalog:"
|
||||
}
|
||||
}
|
||||
6
apps/ssr/postcss.config.mjs
Normal file
6
apps/ssr/postcss.config.mjs
Normal file
@@ -0,0 +1,6 @@
|
||||
const config = {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
}
|
||||
export default config
|
||||
7
apps/ssr/src/app/(pages)/globals.css
Normal file
7
apps/ssr/src/app/(pages)/globals.css
Normal file
@@ -0,0 +1,7 @@
|
||||
@import 'tailwindcss';
|
||||
@plugin '@tailwindcss/typography';
|
||||
@plugin 'tailwind-scrollbar';
|
||||
@plugin 'tailwindcss-animate';
|
||||
@plugin 'tailwindcss-safe-area';
|
||||
@import 'tailwindcss-uikit-colors/v4/macos.css';
|
||||
@plugin '@egoist/tailwindcss-icons';
|
||||
13
apps/ssr/src/app/(pages)/layout.tsx
Normal file
13
apps/ssr/src/app/(pages)/layout.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import './globals.css'
|
||||
|
||||
import { RootProviders } from '~/providers'
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html>
|
||||
<body>
|
||||
<RootProviders>{children}</RootProviders>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
31
apps/ssr/src/app/(pages)/share/iframe/MasonryGallery.tsx
Normal file
31
apps/ssr/src/app/(pages)/share/iframe/MasonryGallery.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
'use client'
|
||||
|
||||
import type { PhotoManifestItem } from '@afilmory/builder'
|
||||
import { useMemo } from 'react'
|
||||
import Masonry from 'react-responsive-masonry'
|
||||
import { useWindowSize } from 'usehooks-ts'
|
||||
|
||||
import { PhotoItem } from './PhotoItem'
|
||||
|
||||
interface MasonryGalleryProps {
|
||||
photos: PhotoManifestItem[]
|
||||
}
|
||||
|
||||
export function MasonryGallery({ photos }: MasonryGalleryProps) {
|
||||
const { width } = useWindowSize()
|
||||
|
||||
const columnsCount = useMemo(() => {
|
||||
if (width < 600) return 1
|
||||
if (width < 800) return 2
|
||||
return 3
|
||||
}, [width])
|
||||
return (
|
||||
<div className="scrollbar-none h-screen overflow-auto">
|
||||
<Masonry gutter={4} columnsCount={columnsCount}>
|
||||
{photos.map((photo) => (
|
||||
<PhotoItem key={photo.id} photo={photo} />
|
||||
))}
|
||||
</Masonry>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
201
apps/ssr/src/app/(pages)/share/iframe/PhotoItem.tsx
Normal file
201
apps/ssr/src/app/(pages)/share/iframe/PhotoItem.tsx
Normal file
@@ -0,0 +1,201 @@
|
||||
'use client'
|
||||
|
||||
import type { PhotoManifestItem } from '@afilmory/builder'
|
||||
import {
|
||||
CarbonIsoOutline,
|
||||
MaterialSymbolsShutterSpeed,
|
||||
StreamlineImageAccessoriesLensesPhotosCameraShutterPicturePhotographyPicturesPhotoLens,
|
||||
TablerAperture,
|
||||
} from '@afilmory/components/icons/index.tsx'
|
||||
import { thumbHashToDataURL } from 'thumbhash'
|
||||
|
||||
import { cn } from '~/lib/cn'
|
||||
|
||||
import { url } from '../../../../../../../config.json'
|
||||
|
||||
const decompressUint8Array = (compressed: string) => {
|
||||
return Uint8Array.from(
|
||||
compressed.match(/.{1,2}/g)!.map((byte) => Number.parseInt(byte, 16)),
|
||||
)
|
||||
}
|
||||
|
||||
interface PhotoItemProps {
|
||||
photo: PhotoManifestItem
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function PhotoItem({ photo, className }: PhotoItemProps) {
|
||||
// 生成 thumbhash 预览
|
||||
const thumbHashDataURL = photo.thumbHash
|
||||
? thumbHashToDataURL(decompressUint8Array(photo.thumbHash))
|
||||
: null
|
||||
|
||||
const ratio = photo.aspectRatio
|
||||
|
||||
// 格式化 EXIF 数据
|
||||
const formatExifData = () => {
|
||||
const { exif } = photo
|
||||
|
||||
// 安全处理:如果 exif 不存在或为空,则返回空对象
|
||||
if (!exif) {
|
||||
return {
|
||||
focalLength35mm: null,
|
||||
iso: null,
|
||||
shutterSpeed: null,
|
||||
aperture: null,
|
||||
}
|
||||
}
|
||||
|
||||
// 等效焦距 (35mm)
|
||||
const focalLength35mm = exif.FocalLengthIn35mmFormat
|
||||
? Number.parseInt(exif.FocalLengthIn35mmFormat)
|
||||
: exif.FocalLength
|
||||
? Number.parseInt(exif.FocalLength)
|
||||
: null
|
||||
|
||||
// ISO
|
||||
const iso = exif.ISO
|
||||
|
||||
// 快门速度
|
||||
const exposureTime = exif.ExposureTime
|
||||
const shutterSpeed = exposureTime ? `${exposureTime}s` : null
|
||||
|
||||
// 光圈
|
||||
const aperture = exif.FNumber ? `f/${exif.FNumber}` : null
|
||||
|
||||
return {
|
||||
focalLength35mm,
|
||||
iso,
|
||||
shutterSpeed,
|
||||
aperture,
|
||||
}
|
||||
}
|
||||
|
||||
const exifData = formatExifData()
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
role="link"
|
||||
onClick={() => {
|
||||
window.open(`${url}/${photo.id}`, '_blank')
|
||||
}}
|
||||
className={cn(
|
||||
'group relative block w-full cursor-pointer overflow-hidden text-left',
|
||||
className,
|
||||
)}
|
||||
style={{
|
||||
paddingTop: `${100 / ratio}%`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'pointer-events-none absolute inset-0 z-[1] flex items-start justify-center',
|
||||
)}
|
||||
>
|
||||
<div className="bg-material-medium mt-4 flex items-center gap-2 rounded-full border border-white/20 px-3 py-1.5 opacity-0 backdrop-blur-[70px] transition-opacity duration-300 group-hover:opacity-100">
|
||||
<i className="i-mingcute-external-link-line size-4 text-white" />
|
||||
<span className="text-sm text-white/80">Open in AFilmory</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="absolute inset-0">
|
||||
<img
|
||||
src={thumbHashDataURL}
|
||||
alt={photo.title}
|
||||
className="absolute inset-0 size-full"
|
||||
loading="lazy"
|
||||
/>
|
||||
<img
|
||||
src={photo.originalUrl}
|
||||
alt={photo.title}
|
||||
className="absolute inset-0 size-full object-cover object-center"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 图片信息和 EXIF 覆盖层 */}
|
||||
|
||||
<div className="@container pointer-events-none">
|
||||
{/* 渐变背景 - 独立的层 */}
|
||||
<div className="pointer-events-none absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100" />
|
||||
|
||||
{/* 内容层 - 独立的层以支持 backdrop-filter */}
|
||||
<div className="absolute inset-x-0 bottom-0 p-4 pb-0 text-white">
|
||||
{/* 基本信息和标签 section */}
|
||||
<div className="mb-3 [&_*]:duration-300">
|
||||
<div className="items-center justify-between @[600px]:flex">
|
||||
<div>
|
||||
<h3 className="mb-2 truncate text-sm font-medium opacity-0 group-hover:opacity-100">
|
||||
{photo.title}
|
||||
</h3>
|
||||
{photo.description && (
|
||||
<p className="mb-2 line-clamp-2 text-sm text-white/80 opacity-0 group-hover:opacity-100">
|
||||
{photo.description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 基本信息 */}
|
||||
<div>
|
||||
<div className="mb-2 flex flex-wrap gap-2 text-xs text-white/80 opacity-0 group-hover:opacity-100">
|
||||
<span>
|
||||
{photo.width} × {photo.height}
|
||||
</span>
|
||||
<span>•</span>
|
||||
<span>{(photo.size / 1024 / 1024).toFixed(1)}MB</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tags */}
|
||||
{photo.tags && photo.tags.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{photo.tags.map((tag) => (
|
||||
<span
|
||||
key={tag}
|
||||
className="rounded-full bg-white/20 px-2 py-0.5 text-xs text-white/90 opacity-0 backdrop-blur-sm group-hover:opacity-100"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-2 pb-4 text-xs @[600px]:grid-cols-4">
|
||||
{exifData.focalLength35mm && (
|
||||
<div className="flex items-center gap-1.5 rounded-md bg-white/10 px-2 py-1 opacity-0 backdrop-blur-md transition-opacity duration-300 group-hover:opacity-100">
|
||||
<StreamlineImageAccessoriesLensesPhotosCameraShutterPicturePhotographyPicturesPhotoLens className="text-white/70" />
|
||||
<span className="text-white/90">
|
||||
{exifData.focalLength35mm}mm
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{exifData.aperture && (
|
||||
<div className="flex items-center gap-1.5 rounded-md bg-white/10 px-2 py-1 opacity-0 backdrop-blur-md transition-opacity duration-300 group-hover:opacity-100">
|
||||
<TablerAperture className="text-white/70" />
|
||||
<span className="text-white/90">{exifData.aperture}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{exifData.shutterSpeed && (
|
||||
<div className="flex items-center gap-1.5 rounded-md bg-white/10 px-2 py-1 opacity-0 backdrop-blur-md transition-opacity duration-300 group-hover:opacity-100">
|
||||
<MaterialSymbolsShutterSpeed className="text-white/70" />
|
||||
<span className="text-white/90">{exifData.shutterSpeed}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{exifData.iso && (
|
||||
<div className="flex items-center gap-1.5 rounded-md bg-white/10 px-2 py-1 opacity-0 backdrop-blur-md transition-opacity duration-300 group-hover:opacity-100">
|
||||
<CarbonIsoOutline className="text-white/70" />
|
||||
<span className="text-white/90">ISO {exifData.iso}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
23
apps/ssr/src/app/(pages)/share/iframe/layout.tsx
Normal file
23
apps/ssr/src/app/(pages)/share/iframe/layout.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
'use client'
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<style jsx global>{`
|
||||
body {
|
||||
color: #ffffff;
|
||||
font-family: -apple-system, system-ui, sans-serif;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #0a0a0a;
|
||||
}
|
||||
`}</style>
|
||||
{children}
|
||||
</>
|
||||
)
|
||||
}
|
||||
44
apps/ssr/src/app/(pages)/share/iframe/page.tsx
Normal file
44
apps/ssr/src/app/(pages)/share/iframe/page.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import type { PhotoManifestItem } from '@afilmory/builder'
|
||||
import { notFound } from 'next/navigation'
|
||||
|
||||
import { photoLoader } from '~/lib/photo-loader'
|
||||
|
||||
import { MasonryGallery } from './MasonryGallery'
|
||||
import { PhotoItem } from './PhotoItem'
|
||||
|
||||
export default async function Page({
|
||||
searchParams,
|
||||
}: NextPageExtractedParams<unknown>) {
|
||||
const { id } = await searchParams
|
||||
|
||||
let photos: PhotoManifestItem[] = []
|
||||
|
||||
if (!id) return notFound()
|
||||
if (typeof id === 'string') {
|
||||
const photo = await photoLoader.getPhoto(id)
|
||||
if (!photo) {
|
||||
notFound()
|
||||
}
|
||||
photos = [photo]
|
||||
} else {
|
||||
photos = await photoLoader.getPhotos(id)
|
||||
if (photos.length === 0) {
|
||||
notFound()
|
||||
}
|
||||
}
|
||||
|
||||
if (photos.length === 1) {
|
||||
return (
|
||||
<PhotoItem
|
||||
photo={photos[0]}
|
||||
className="absolute inset-0 size-full !pt-0"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-screen bg-[#0a0a0a] text-white">
|
||||
<MasonryGallery photos={photos} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
5
apps/ssr/src/lib/cn.ts
Normal file
5
apps/ssr/src/lib/cn.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import type { ClassValue } from 'clsx'
|
||||
import clsx from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs))
|
||||
@@ -12,6 +12,7 @@ export const injectConfigToDocument = (document: OnlyHTMLDocument) => {
|
||||
const $config = document.head.querySelector('#config')
|
||||
const injectConfigBase = {
|
||||
useApi: DbManager.shared.isEnabled(),
|
||||
useNext: true,
|
||||
}
|
||||
if ($config) {
|
||||
$config.innerHTML = `window.__CONFIG__ = ${JSON.stringify(injectConfigBase)}`
|
||||
|
||||
@@ -17,7 +17,10 @@ class PhotoLoader {
|
||||
})
|
||||
}
|
||||
|
||||
getPhotos() {
|
||||
getPhotos(ids?: string[]) {
|
||||
if (ids) {
|
||||
return this.photos.filter((photo) => ids.includes(photo.id))
|
||||
}
|
||||
return this.photos
|
||||
}
|
||||
|
||||
|
||||
3
apps/ssr/src/providers/index.tsx
Normal file
3
apps/ssr/src/providers/index.tsx
Normal file
@@ -0,0 +1,3 @@
|
||||
export const RootProviders = ({ children }: { children: React.ReactNode }) => {
|
||||
return <>{children}</>
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"jsx": "preserve",
|
||||
"plugins": [
|
||||
{
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
"swiper": "11.2.8",
|
||||
"swr": "2.3.3",
|
||||
"tailwind-merge": "3.3.1",
|
||||
"tailwind-variants": "1.0.0",
|
||||
"thumbhash": "0.1.1",
|
||||
"tiff": "^7.0.0",
|
||||
"usehooks-ts": "3.1.1",
|
||||
@@ -77,11 +78,10 @@
|
||||
"zustand": "5.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@egoist/tailwindcss-icons": "1.9.0",
|
||||
"@iconify-json/mingcute": "1.2.3",
|
||||
"@tailwindcss/container-queries": "0.1.1",
|
||||
"@tailwindcss/postcss": "4.1.11",
|
||||
"@tailwindcss/typography": "0.5.16",
|
||||
"@egoist/tailwindcss-icons": "catalog:",
|
||||
"@iconify-json/mingcute": "catalog:",
|
||||
"@tailwindcss/postcss": "catalog:",
|
||||
"@tailwindcss/typography": "catalog:",
|
||||
"@tailwindcss/vite": "4.1.11",
|
||||
"@types/node": "24.0.4",
|
||||
"@types/react": "19.1.8",
|
||||
@@ -92,17 +92,17 @@
|
||||
"code-inspector-plugin": "0.20.12",
|
||||
"daisyui": "5.0.43",
|
||||
"execa": "9.6.0",
|
||||
"kolorist": "1.8.0",
|
||||
"postcss": "8.5.6",
|
||||
"postcss-import": "16.1.1",
|
||||
"postcss-js": "4.0.1",
|
||||
"react-compiler-runtime": "19.1.0-rc.2",
|
||||
"simple-git-hooks": "2.13.0",
|
||||
"tailwind-scrollbar": "4.0.2",
|
||||
"tailwind-variants": "1.0.0",
|
||||
"tailwindcss": "4.1.11",
|
||||
"tailwindcss-animate": "1.0.7",
|
||||
"tailwindcss-safe-area": "0.6.0",
|
||||
"tailwindcss-uikit-colors": "1.0.0-alpha.1",
|
||||
"tailwind-scrollbar": "catalog:",
|
||||
"tailwindcss": "catalog:",
|
||||
"tailwindcss-animate": "catalog:",
|
||||
"tailwindcss-safe-area": "catalog:",
|
||||
"tailwindcss-uikit-colors": "catalog:",
|
||||
"unplugin-ast": "0.15.0",
|
||||
"vite-plugin-html": "3.2.2"
|
||||
}
|
||||
|
||||
@@ -156,59 +156,64 @@ export const ExifPanel: FC<{
|
||||
)}
|
||||
</div>
|
||||
|
||||
{formattedExifData && (
|
||||
<div>
|
||||
<h4 className="my-2 text-sm font-medium text-white/80">
|
||||
{t('exif.capture.parameters')}
|
||||
</h4>
|
||||
<div className={`grid grid-cols-2 gap-2`}>
|
||||
{formattedExifData.focalLength35mm && (
|
||||
<div className="flex h-6 items-center gap-2 rounded-md bg-white/10 px-2">
|
||||
<StreamlineImageAccessoriesLensesPhotosCameraShutterPicturePhotographyPicturesPhotoLens className="text-sm text-white/70" />
|
||||
<span className="text-xs">
|
||||
{formattedExifData.focalLength35mm}mm
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{formattedExifData &&
|
||||
(formattedExifData.shutterSpeed ||
|
||||
formattedExifData.iso ||
|
||||
formattedExifData.aperture ||
|
||||
formattedExifData.exposureBias ||
|
||||
formattedExifData.focalLength35mm) && (
|
||||
<div>
|
||||
<h4 className="my-2 text-sm font-medium text-white/80">
|
||||
{t('exif.capture.parameters')}
|
||||
</h4>
|
||||
<div className={`grid grid-cols-2 gap-2`}>
|
||||
{formattedExifData.focalLength35mm && (
|
||||
<div className="flex h-6 items-center gap-2 rounded-md bg-white/10 px-2">
|
||||
<StreamlineImageAccessoriesLensesPhotosCameraShutterPicturePhotographyPicturesPhotoLens className="text-sm text-white/70" />
|
||||
<span className="text-xs">
|
||||
{formattedExifData.focalLength35mm}mm
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{formattedExifData.aperture && (
|
||||
<div className="flex h-6 items-center gap-2 rounded-md bg-white/10 px-2">
|
||||
<TablerAperture className="text-sm text-white/70" />
|
||||
<span className="text-xs">
|
||||
{formattedExifData.aperture}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{formattedExifData.aperture && (
|
||||
<div className="flex h-6 items-center gap-2 rounded-md bg-white/10 px-2">
|
||||
<TablerAperture className="text-sm text-white/70" />
|
||||
<span className="text-xs">
|
||||
{formattedExifData.aperture}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{formattedExifData.shutterSpeed && (
|
||||
<div className="flex h-6 items-center gap-2 rounded-md bg-white/10 px-2">
|
||||
<MaterialSymbolsShutterSpeed className="text-sm text-white/70" />
|
||||
<span className="text-xs">
|
||||
{formattedExifData.shutterSpeed}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{formattedExifData.shutterSpeed && (
|
||||
<div className="flex h-6 items-center gap-2 rounded-md bg-white/10 px-2">
|
||||
<MaterialSymbolsShutterSpeed className="text-sm text-white/70" />
|
||||
<span className="text-xs">
|
||||
{formattedExifData.shutterSpeed}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{formattedExifData.iso && (
|
||||
<div className="flex h-6 items-center gap-2 rounded-md bg-white/10 px-2">
|
||||
<CarbonIsoOutline className="text-sm text-white/70" />
|
||||
<span className="text-xs">
|
||||
ISO {formattedExifData.iso}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{formattedExifData.iso && (
|
||||
<div className="flex h-6 items-center gap-2 rounded-md bg-white/10 px-2">
|
||||
<CarbonIsoOutline className="text-sm text-white/70" />
|
||||
<span className="text-xs">
|
||||
ISO {formattedExifData.iso}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{formattedExifData.exposureBias && (
|
||||
<div className="flex h-6 items-center gap-2 rounded-md bg-white/10 px-2">
|
||||
<MaterialSymbolsExposure className="text-sm text-white/70" />
|
||||
<span className="text-xs">
|
||||
{formattedExifData.exposureBias}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{formattedExifData.exposureBias && (
|
||||
<div className="flex h-6 items-center gap-2 rounded-md bg-white/10 px-2">
|
||||
<MaterialSymbolsExposure className="text-sm text-white/70" />
|
||||
<span className="text-xs">
|
||||
{formattedExifData.exposureBias}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
|
||||
{/* 标签信息 - 移到基本信息 section 内 */}
|
||||
{currentPhoto.tags && currentPhoto.tags.length > 0 && (
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { siteConfig } from '@config'
|
||||
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
|
||||
import { AnimatePresence, m } from 'motion/react'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { injectConfig } from '~/config'
|
||||
import { clsxm } from '~/lib/cn'
|
||||
import { Spring } from '~/lib/spring'
|
||||
import type { PhotoManifest } from '~/types/photo'
|
||||
@@ -121,6 +123,23 @@ export const SharePanel = ({ photo, trigger, blobSrc }: SharePanelProps) => {
|
||||
}
|
||||
}, [t])
|
||||
|
||||
const handleCopyEmbedCode = useCallback(async () => {
|
||||
try {
|
||||
const embedCode = `<iframe
|
||||
src="${siteConfig.url}/share/iframe?id=${photo.id}"
|
||||
height="500"
|
||||
className="w-full"
|
||||
allowTransparency
|
||||
sandbox="allow-scripts allow-same-origin allow-popups"
|
||||
/>`
|
||||
await navigator.clipboard.writeText(embedCode)
|
||||
toast.success(t('photo.share.embed.copied'))
|
||||
setIsOpen(false)
|
||||
} catch {
|
||||
toast.error(t('photo.share.copy.failed'))
|
||||
}
|
||||
}, [photo.id, t])
|
||||
|
||||
const handleSocialShare = useCallback(
|
||||
(url: string) => {
|
||||
const shareUrl = encodeURIComponent(window.location.href)
|
||||
@@ -160,6 +179,13 @@ export const SharePanel = ({ photo, trigger, blobSrc }: SharePanelProps) => {
|
||||
icon: 'i-mingcute-link-line',
|
||||
action: handleCopyLink,
|
||||
},
|
||||
{
|
||||
id: 'copy-embed',
|
||||
label: t('photo.share.embed.code'),
|
||||
icon: 'i-mingcute-code-line',
|
||||
action: handleCopyEmbedCode,
|
||||
color: 'text-purple-500',
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
@@ -208,7 +234,7 @@ export const SharePanel = ({ photo, trigger, blobSrc }: SharePanelProps) => {
|
||||
{t('photo.share.social.media')}
|
||||
</h4>
|
||||
</div>
|
||||
<div className="flex justify-center gap-4">
|
||||
<div className="flex gap-6 px-2">
|
||||
{socialOptions.map((option) => (
|
||||
<button
|
||||
key={option.id}
|
||||
@@ -240,7 +266,45 @@ export const SharePanel = ({ photo, trigger, blobSrc }: SharePanelProps) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 功能选项 - 第二排 */}
|
||||
{/* 嵌入代码 - 第二排 */}
|
||||
{injectConfig.useNext && (
|
||||
<div className="mb-6">
|
||||
<div className="mb-3">
|
||||
<h4 className="text-text-secondary text-xs font-medium tracking-wide uppercase">
|
||||
{t('photo.share.embed.code')}
|
||||
</h4>
|
||||
<p className="text-text-tertiary mt-1 text-xs">
|
||||
{t('photo.share.embed.description')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div className="bg-fill-secondary/50 border-border/10 rounded-lg border p-3">
|
||||
<code className="text-text-secondary font-mono text-xs break-all whitespace-pre select-all">
|
||||
{`<iframe
|
||||
src="${siteConfig.url}/share/iframe?id=${photo.id}"
|
||||
height="500"
|
||||
style="width: 100%;"
|
||||
allowTransparency
|
||||
sandbox="allow-scripts allow-same-origin allow-popups"
|
||||
/>`}
|
||||
</code>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className={clsxm(
|
||||
'absolute top-2 right-2 flex items-center justify-center',
|
||||
'size-7 rounded-md bg-fill-tertiary/80 hover:bg-fill-tertiary backdrop-blur-3xl',
|
||||
'transition-colors duration-200 group',
|
||||
)}
|
||||
onClick={handleCopyEmbedCode}
|
||||
>
|
||||
<i className="i-mingcute-copy-line text-text-secondary group-hover:text-text size-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 功能选项 - 第三排 */}
|
||||
<div>
|
||||
<div className="mb-3">
|
||||
<h4 className="text-text-secondary text-xs font-medium tracking-wide uppercase">
|
||||
@@ -248,40 +312,42 @@ export const SharePanel = ({ photo, trigger, blobSrc }: SharePanelProps) => {
|
||||
</h4>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-1">
|
||||
{actionOptions.map((option) => (
|
||||
<button
|
||||
key={option.id}
|
||||
type="button"
|
||||
className={clsxm(
|
||||
'relative flex cursor-pointer select-none items-center rounded-lg px-2 py-2',
|
||||
'text-sm outline-none transition-all duration-200',
|
||||
'hover:bg-fill-secondary/80 active:bg-fill-secondary',
|
||||
'group',
|
||||
)}
|
||||
onClick={() => option.action()}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className={clsxm(
|
||||
'flex size-7 items-center justify-center rounded-full',
|
||||
'bg-fill-tertiary/80 group-hover:bg-fill-tertiary',
|
||||
'transition-colors duration-200',
|
||||
)}
|
||||
>
|
||||
<i
|
||||
{actionOptions
|
||||
.filter((option) => option.id !== 'copy-embed')
|
||||
.map((option) => (
|
||||
<button
|
||||
key={option.id}
|
||||
type="button"
|
||||
className={clsxm(
|
||||
'relative flex cursor-pointer select-none items-center rounded-lg px-2 py-2',
|
||||
'text-sm outline-none transition-all duration-200',
|
||||
'hover:bg-fill-secondary/80 active:bg-fill-secondary',
|
||||
'group',
|
||||
)}
|
||||
onClick={() => option.action()}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className={clsxm(
|
||||
option.icon,
|
||||
'size-3.5',
|
||||
option.color || 'text-text-secondary',
|
||||
'flex size-7 items-center justify-center rounded-full',
|
||||
'bg-fill-tertiary/80 group-hover:bg-fill-tertiary',
|
||||
'transition-colors duration-200',
|
||||
)}
|
||||
/>
|
||||
>
|
||||
<i
|
||||
className={clsxm(
|
||||
option.icon,
|
||||
'size-3.5',
|
||||
option.color || 'text-text-secondary',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-text text-xs font-medium">
|
||||
{option.label}
|
||||
</span>
|
||||
</div>
|
||||
<span className="text-text text-xs font-medium">
|
||||
{option.label}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</m.div>
|
||||
|
||||
@@ -215,7 +215,11 @@ export const formatExifData = (exif: PickedExif | null) => {
|
||||
|
||||
// 快门速度
|
||||
const exposureTime = exif.ExposureTime
|
||||
const shutterSpeed = `${exposureTime}s`
|
||||
const shutterSpeed = exposureTime
|
||||
? `${exposureTime}s`
|
||||
: exif.ShutterSpeedValue
|
||||
? `${exif.ShutterSpeedValue}s`
|
||||
: null
|
||||
|
||||
// 光圈
|
||||
const aperture = exif.FNumber ? `f/${exif.FNumber}` : null
|
||||
|
||||
@@ -2,6 +2,7 @@ import { merge } from 'es-toolkit/compat'
|
||||
|
||||
const defaultInjectConfig = {
|
||||
useApi: false,
|
||||
useNext: false,
|
||||
}
|
||||
|
||||
export const injectConfig = merge(defaultInjectConfig, __CONFIG__)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { domMax as default } from 'motion/react'
|
||||
@@ -31,7 +31,7 @@ export function CarbonIsoOutline(props: SVGProps<SVGSVGElement>) {
|
||||
viewBox="0 0 32 32"
|
||||
{...props}
|
||||
>
|
||||
{/* Icon from Carbon by IBM - undefined */}
|
||||
{/* Icon from Carbon by IBM */}
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M24 21h-3a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2m-3-8v6h3v-6zm-6 8h-5v-2h5v-2h-3a2 2 0 0 1-2-2v-2a2 2 0 0 1 2-2h5v2h-5v2h3a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2M6 11h2v10H6z"
|
||||
|
||||
@@ -15,7 +15,7 @@ import { ImageLoaderManager } from '~/lib/image-loader-manager'
|
||||
import { getImageFormat } from '~/lib/image-utils'
|
||||
import type { PhotoManifest } from '~/types/photo'
|
||||
|
||||
export const PhotoMasonryItem = ({
|
||||
export const MasonryPhotoItem = ({
|
||||
data,
|
||||
width,
|
||||
index: _,
|
||||
@@ -88,7 +88,7 @@ export const PhotoMasonryItem = ({
|
||||
|
||||
// 快门速度
|
||||
const exposureTime = exif.ExposureTime
|
||||
const shutterSpeed = `${exposureTime}s`
|
||||
const shutterSpeed = exposureTime ? `${exposureTime}s` : null
|
||||
|
||||
// 光圈
|
||||
const aperture = exif.FNumber ? `f/${exif.FNumber}` : null
|
||||
@@ -18,7 +18,7 @@ import { ActionGroup, ActionPanel } from './ActionGroup'
|
||||
import { FloatingActionButton } from './FloatingActionButton'
|
||||
import { Masonry } from './Masonic'
|
||||
import { MasonryHeaderMasonryItem } from './MasonryHeaderMasonryItem'
|
||||
import { PhotoMasonryItem } from './PhotoMasonryItem'
|
||||
import { MasonryPhotoItem } from './MasonryPhotoItem'
|
||||
|
||||
class MasonryHeaderItem {
|
||||
static default = new MasonryHeaderItem()
|
||||
@@ -273,7 +273,7 @@ export const MasonryItem = memo(
|
||||
animate="visible"
|
||||
onAnimationComplete={shouldAnimate ? onAnimationComplete : undefined}
|
||||
>
|
||||
<PhotoMasonryItem
|
||||
<MasonryPhotoItem
|
||||
data={data as PhotoManifest}
|
||||
width={width}
|
||||
index={index}
|
||||
|
||||
33
apps/web/src/pages/(debug)/iframe.tsx
Normal file
33
apps/web/src/pages/(debug)/iframe.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { ScrollArea } from '~/components/ui/scroll-areas/ScrollArea'
|
||||
|
||||
export const Component = () => {
|
||||
return (
|
||||
<ScrollArea rootClassName="h-screen">
|
||||
<div className="mx-auto w-[60ch] py-8">
|
||||
<iframe
|
||||
src="http://localhost:1924/share/iframe?id=DSCF0842"
|
||||
height={500}
|
||||
className="w-full"
|
||||
allowTransparency
|
||||
sandbox="allow-scripts allow-same-origin allow-popups"
|
||||
/>
|
||||
|
||||
<iframe
|
||||
src="http://localhost:1924/share/iframe?id=DSCF0842"
|
||||
height={400}
|
||||
className="w-[400px]"
|
||||
allowTransparency
|
||||
sandbox="allow-scripts allow-same-origin allow-popups"
|
||||
/>
|
||||
|
||||
<iframe
|
||||
src="http://localhost:1924/share/iframe?id=IMG_0030&id=DSCF0842"
|
||||
height={400}
|
||||
className="w-full"
|
||||
allowTransparency
|
||||
sandbox="allow-scripts allow-same-origin allow-popups"
|
||||
/>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
)
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import { fileURLToPath } from 'node:url'
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { codeInspectorPlugin } from 'code-inspector-plugin'
|
||||
import { cyan, dim, green } from 'kolorist'
|
||||
import type { PluginOption, ViteDevServer } from 'vite'
|
||||
import { defineConfig } from 'vite'
|
||||
import { analyzer } from 'vite-bundle-analyzer'
|
||||
import { checker } from 'vite-plugin-checker'
|
||||
@@ -21,6 +23,19 @@ import { localesJsonPlugin } from './plugins/vite/locales-json'
|
||||
import { manifestInjectPlugin } from './plugins/vite/manifest-inject'
|
||||
import { ogImagePlugin } from './plugins/vite/og-image-plugin'
|
||||
|
||||
const devPrint = (): PluginOption => ({
|
||||
name: 'dev-print',
|
||||
configureServer(server: ViteDevServer) {
|
||||
server.printUrls = () => {
|
||||
console.info(
|
||||
` ${green('➜')} ${dim('Next.js SSR')}: ${cyan(
|
||||
'http://localhost:1924',
|
||||
)}`,
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
if (process.env.CI) {
|
||||
@@ -90,6 +105,8 @@ export default defineConfig({
|
||||
},
|
||||
}),
|
||||
process.env.analyzer && analyzer(),
|
||||
|
||||
devPrint(),
|
||||
],
|
||||
server: {
|
||||
port: !DEV_NEXT_JS ? 1924 : 3000, // 1924 年首款 35mm 相机问世
|
||||
|
||||
@@ -235,6 +235,9 @@
|
||||
"photo.share.copy.failed": "Copy failed",
|
||||
"photo.share.copy.link": "Copy Link",
|
||||
"photo.share.default.title": "Photo Share",
|
||||
"photo.share.embed.code": "Embed Code",
|
||||
"photo.share.embed.copied": "Embed code copied to clipboard",
|
||||
"photo.share.embed.description": "Copy this code to embed the photo on your website",
|
||||
"photo.share.link.copied": "Link copied to clipboard",
|
||||
"photo.share.social.media": "Social Media",
|
||||
"photo.share.system": "System Share",
|
||||
|
||||
@@ -233,6 +233,9 @@
|
||||
"photo.share.copy.failed": "コピーに失敗しました",
|
||||
"photo.share.copy.link": "リンクをコピー",
|
||||
"photo.share.default.title": "写真の共有",
|
||||
"photo.share.embed.code": "埋め込みコード",
|
||||
"photo.share.embed.copied": "埋め込みコードがクリップボードにコピーされました",
|
||||
"photo.share.embed.description": "このコードをコピーして、あなたのウェブサイトに写真を埋め込んでください",
|
||||
"photo.share.link.copied": "リンクがクリップボードにコピーされました",
|
||||
"photo.share.social.media": "ソーシャルメディア",
|
||||
"photo.share.system": "システム共有",
|
||||
|
||||
@@ -233,6 +233,9 @@
|
||||
"photo.share.copy.failed": "복사 실패",
|
||||
"photo.share.copy.link": "링크 복사",
|
||||
"photo.share.default.title": "사진 공유",
|
||||
"photo.share.embed.code": "임베드 코드",
|
||||
"photo.share.embed.copied": "임베드 코드를 클립보드에 복사했습니다",
|
||||
"photo.share.embed.description": "이 코드를 복사하여 웹사이트에 사진을 임베드하세요",
|
||||
"photo.share.link.copied": "링크를 클립보드에 복사했습니다",
|
||||
"photo.share.social.media": "소셜 미디어",
|
||||
"photo.share.system": "시스템 공유",
|
||||
|
||||
@@ -235,6 +235,9 @@
|
||||
"photo.share.copy.failed": "复制失败",
|
||||
"photo.share.copy.link": "复制链接",
|
||||
"photo.share.default.title": "照片分享",
|
||||
"photo.share.embed.code": "嵌入代码",
|
||||
"photo.share.embed.copied": "嵌入代码已复制到剪贴板",
|
||||
"photo.share.embed.description": "复制此代码以在您的网站中嵌入照片",
|
||||
"photo.share.link.copied": "链接已复制到剪贴板",
|
||||
"photo.share.social.media": "社交媒体",
|
||||
"photo.share.system": "系统分享",
|
||||
|
||||
@@ -233,6 +233,9 @@
|
||||
"photo.share.copy.failed": "複製失敗",
|
||||
"photo.share.copy.link": "複製連結",
|
||||
"photo.share.default.title": "照片分享",
|
||||
"photo.share.embed.code": "嵌入代碼",
|
||||
"photo.share.embed.copied": "嵌入代碼已複製到剪貼簿",
|
||||
"photo.share.embed.description": "複製此代碼以在您的網站中嵌入照片",
|
||||
"photo.share.link.copied": "連結已複製到剪貼簿",
|
||||
"photo.share.social.media": "社交媒體",
|
||||
"photo.share.system": "系統分享",
|
||||
|
||||
@@ -233,6 +233,9 @@
|
||||
"photo.share.copy.failed": "複製失敗",
|
||||
"photo.share.copy.link": "複製連結",
|
||||
"photo.share.default.title": "照片分享",
|
||||
"photo.share.embed.code": "嵌入代碼",
|
||||
"photo.share.embed.copied": "嵌入代碼已複製到剪貼簿",
|
||||
"photo.share.embed.description": "複製此代碼以在您的網站中嵌入照片",
|
||||
"photo.share.link.copied": "連結已複製到剪貼簿",
|
||||
"photo.share.social.media": "社群媒體",
|
||||
"photo.share.system": "系統分享",
|
||||
|
||||
11
packages/components/package.json
Normal file
11
packages/components/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@afilmory/components",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"exports": {
|
||||
"./*": "./src/*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19"
|
||||
}
|
||||
}
|
||||
107
packages/components/src/icons/index.tsx
Normal file
107
packages/components/src/icons/index.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import type { SVGProps } from 'react'
|
||||
|
||||
export function TablerAperture(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
{/* Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE */}
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0-18 0m.6 3h10.55M6.551 4.938l3.26 10.034m7.221-10.336l-8.535 6.201m12.062 3.673l-8.535-6.201m.233 12.607l3.261-10.034"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function CarbonIsoOutline(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 32 32"
|
||||
{...props}
|
||||
>
|
||||
{/* Icon from Carbon by IBM */}
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M24 21h-3a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2m-3-8v6h3v-6zm-6 8h-5v-2h5v-2h-3a2 2 0 0 1-2-2v-2a2 2 0 0 1 2-2h5v2h-5v2h3a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2M6 11h2v10H6z"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M28 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2M4 24V8h24v16Z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function MaterialSymbolsShutterSpeed(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
{/* Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE */}
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M9 3V1h6v2zm3 19q-1.875 0-3.512-.712T5.625 19.35T3.7 16.487T3 13t.713-3.488T5.65 6.65t2.863-1.937T12 4q1.575 0 3 .525T17.6 6l1.45-1.45l1.4 1.4l-1.4 1.45q.9 1.175 1.425 2.6T21 13q0 1.85-.7 3.488t-1.925 2.862t-2.863 1.938T12 22m0-2q2.925 0 4.963-2.037T19 13t-2.037-4.962T12 6T7.038 8.038T5 13t2.038 4.963T12 20m0-9h5.65q-.45-1.275-1.4-2.238T14.1 7.375zm-1.725 1L13.1 7.1q-1.275-.25-2.562.075t-2.363 1.2zM6.1 14h4.175L7.45 9.1q-.875.975-1.225 2.263T6.1 14m3.8 4.625L12 15H6.35q.425 1.25 1.388 2.225t2.162 1.4m1 .275q1.425.275 2.725-.112t2.2-1.163L13.725 14zm5.65-2q.9-1.025 1.238-2.287T17.9 12h-4.175z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function StreamlineImageAccessoriesLensesPhotosCameraShutterPicturePhotographyPicturesPhotoLens(
|
||||
props: SVGProps<SVGSVGElement>,
|
||||
) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 14 14"
|
||||
{...props}
|
||||
>
|
||||
{/* Icon from Streamline by Streamline - https://creativecommons.org/licenses/by/4.0/ */}
|
||||
<g
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<circle cx="7" cy="7" r="6.5" />
|
||||
<circle cx="7" cy="7" r="2.5" />
|
||||
<path d="M4.5 7V1M7 4.5h6M9.5 7v6M7 9.5H1" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function MaterialSymbolsExposure(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
{/* Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE */}
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M5 21q-.825 0-1.412-.587T3 19V5q0-.825.588-1.412T5 3h14q.825 0 1.413.588T21 5v14q0 .825-.587 1.413T19 21zm0-2h14V5zm9.5-1v-2h-2v-1.5h2v-2H16v2h2V16h-2v2zM6 8.5h5V7H6z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
348
pnpm-lock.yaml
generated
348
pnpm-lock.yaml
generated
@@ -6,12 +6,42 @@ settings:
|
||||
|
||||
catalogs:
|
||||
default:
|
||||
'@egoist/tailwindcss-icons':
|
||||
specifier: 1.9.0
|
||||
version: 1.9.0
|
||||
'@iconify-json/mingcute':
|
||||
specifier: 1.2.3
|
||||
version: 1.2.3
|
||||
'@t3-oss/env-core':
|
||||
specifier: 0.13.8
|
||||
version: 0.13.8
|
||||
'@tailwindcss/postcss':
|
||||
specifier: 4.1.11
|
||||
version: 4.1.11
|
||||
'@tailwindcss/typography':
|
||||
specifier: 0.5.16
|
||||
version: 0.5.16
|
||||
dotenv-expand:
|
||||
specifier: 12.0.2
|
||||
version: 12.0.2
|
||||
tailwind-scrollbar:
|
||||
specifier: 4.0.2
|
||||
version: 4.0.2
|
||||
tailwind-variants:
|
||||
specifier: 1.0.0
|
||||
version: 1.0.0
|
||||
tailwindcss:
|
||||
specifier: 4.1.11
|
||||
version: 4.1.11
|
||||
tailwindcss-animate:
|
||||
specifier: 1.0.7
|
||||
version: 1.0.7
|
||||
tailwindcss-safe-area:
|
||||
specifier: 0.6.0
|
||||
version: 0.6.0
|
||||
tailwindcss-uikit-colors:
|
||||
specifier: 1.0.0-alpha.1
|
||||
version: 1.0.0-alpha.1
|
||||
typescript:
|
||||
specifier: 5.8.3
|
||||
version: 5.8.3
|
||||
@@ -99,15 +129,24 @@ importers:
|
||||
|
||||
apps/ssr:
|
||||
dependencies:
|
||||
'@afilmory/components':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/components
|
||||
'@afilmory/data':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/data
|
||||
'@t3-oss/env-nextjs':
|
||||
specifier: 0.13.8
|
||||
version: 0.13.8(typescript@5.8.3)(zod@3.25.67)
|
||||
clsx:
|
||||
specifier: 2.1.1
|
||||
version: 2.1.1
|
||||
drizzle-orm:
|
||||
specifier: 0.44.2
|
||||
version: 0.44.2(@types/pg@8.15.4)(@vercel/postgres@0.10.0)(pg@8.16.2)(postgres@3.4.7)
|
||||
es-toolkit:
|
||||
specifier: 1.39.5
|
||||
version: 1.39.5
|
||||
linkedom:
|
||||
specifier: 0.18.11
|
||||
version: 0.18.11
|
||||
@@ -123,10 +162,46 @@ importers:
|
||||
react-dom:
|
||||
specifier: 19.1.0
|
||||
version: 19.1.0(react@19.1.0)
|
||||
react-masonry:
|
||||
specifier: 1.0.7
|
||||
version: 1.0.7
|
||||
react-photo-view:
|
||||
specifier: 1.2.7
|
||||
version: 1.2.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
react-responsive-masonry:
|
||||
specifier: 2.7.1
|
||||
version: 2.7.1
|
||||
react-use:
|
||||
specifier: 17.6.0
|
||||
version: 17.6.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
tailwind-merge:
|
||||
specifier: 3.3.1
|
||||
version: 3.3.1
|
||||
tailwind-variants:
|
||||
specifier: 'catalog:'
|
||||
version: 1.0.0(tailwindcss@4.1.11)
|
||||
thumbhash:
|
||||
specifier: 0.1.1
|
||||
version: 0.1.1
|
||||
usehooks-ts:
|
||||
specifier: 3.1.1
|
||||
version: 3.1.1(react@19.1.0)
|
||||
zod:
|
||||
specifier: 'catalog:'
|
||||
version: 3.25.67
|
||||
devDependencies:
|
||||
'@egoist/tailwindcss-icons':
|
||||
specifier: 'catalog:'
|
||||
version: 1.9.0(tailwindcss@4.1.11)
|
||||
'@iconify-json/mingcute':
|
||||
specifier: 'catalog:'
|
||||
version: 1.2.3
|
||||
'@tailwindcss/postcss':
|
||||
specifier: 'catalog:'
|
||||
version: 4.1.11
|
||||
'@tailwindcss/typography':
|
||||
specifier: 'catalog:'
|
||||
version: 0.5.16(tailwindcss@4.1.11)
|
||||
'@types/node':
|
||||
specifier: 24.0.4
|
||||
version: 24.0.4
|
||||
@@ -154,6 +229,24 @@ importers:
|
||||
next:
|
||||
specifier: 15.3.4
|
||||
version: 15.3.4(@babel/core@7.27.1)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
postcss:
|
||||
specifier: 8.5.6
|
||||
version: 8.5.6
|
||||
tailwind-scrollbar:
|
||||
specifier: 'catalog:'
|
||||
version: 4.0.2(react@19.1.0)(tailwindcss@4.1.11)
|
||||
tailwindcss:
|
||||
specifier: 'catalog:'
|
||||
version: 4.1.11
|
||||
tailwindcss-animate:
|
||||
specifier: 'catalog:'
|
||||
version: 1.0.7(tailwindcss@4.1.11)
|
||||
tailwindcss-safe-area:
|
||||
specifier: 'catalog:'
|
||||
version: 0.6.0(tailwindcss@4.1.11)
|
||||
tailwindcss-uikit-colors:
|
||||
specifier: 'catalog:'
|
||||
version: 1.0.0-alpha.1
|
||||
|
||||
apps/ssr/sdk:
|
||||
dependencies:
|
||||
@@ -323,6 +416,9 @@ importers:
|
||||
tailwind-merge:
|
||||
specifier: 3.3.1
|
||||
version: 3.3.1
|
||||
tailwind-variants:
|
||||
specifier: 1.0.0
|
||||
version: 1.0.0(tailwindcss@4.1.11)
|
||||
thumbhash:
|
||||
specifier: 0.1.1
|
||||
version: 0.1.1
|
||||
@@ -343,19 +439,16 @@ importers:
|
||||
version: 5.0.5(@types/react@19.1.8)(immer@10.1.1)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0))
|
||||
devDependencies:
|
||||
'@egoist/tailwindcss-icons':
|
||||
specifier: 1.9.0
|
||||
specifier: 'catalog:'
|
||||
version: 1.9.0(tailwindcss@4.1.11)
|
||||
'@iconify-json/mingcute':
|
||||
specifier: 1.2.3
|
||||
specifier: 'catalog:'
|
||||
version: 1.2.3
|
||||
'@tailwindcss/container-queries':
|
||||
specifier: 0.1.1
|
||||
version: 0.1.1(tailwindcss@4.1.11)
|
||||
'@tailwindcss/postcss':
|
||||
specifier: 4.1.11
|
||||
specifier: 'catalog:'
|
||||
version: 4.1.11
|
||||
'@tailwindcss/typography':
|
||||
specifier: 0.5.16
|
||||
specifier: 'catalog:'
|
||||
version: 0.5.16(tailwindcss@4.1.11)
|
||||
'@tailwindcss/vite':
|
||||
specifier: 4.1.11
|
||||
@@ -387,6 +480,9 @@ importers:
|
||||
execa:
|
||||
specifier: 9.6.0
|
||||
version: 9.6.0
|
||||
kolorist:
|
||||
specifier: 1.8.0
|
||||
version: 1.8.0
|
||||
postcss:
|
||||
specifier: 8.5.6
|
||||
version: 8.5.6
|
||||
@@ -403,22 +499,19 @@ importers:
|
||||
specifier: 2.13.0
|
||||
version: 2.13.0
|
||||
tailwind-scrollbar:
|
||||
specifier: 4.0.2
|
||||
specifier: 'catalog:'
|
||||
version: 4.0.2(react@19.1.0)(tailwindcss@4.1.11)
|
||||
tailwind-variants:
|
||||
specifier: 1.0.0
|
||||
version: 1.0.0(tailwindcss@4.1.11)
|
||||
tailwindcss:
|
||||
specifier: 4.1.11
|
||||
specifier: 'catalog:'
|
||||
version: 4.1.11
|
||||
tailwindcss-animate:
|
||||
specifier: 1.0.7
|
||||
specifier: 'catalog:'
|
||||
version: 1.0.7(tailwindcss@4.1.11)
|
||||
tailwindcss-safe-area:
|
||||
specifier: 0.6.0
|
||||
specifier: 'catalog:'
|
||||
version: 0.6.0(tailwindcss@4.1.11)
|
||||
tailwindcss-uikit-colors:
|
||||
specifier: 1.0.0-alpha.1
|
||||
specifier: 'catalog:'
|
||||
version: 1.0.0-alpha.1
|
||||
unplugin-ast:
|
||||
specifier: 0.15.0
|
||||
@@ -463,6 +556,12 @@ importers:
|
||||
specifier: 0.1.1
|
||||
version: 0.1.1
|
||||
|
||||
packages/components:
|
||||
dependencies:
|
||||
react:
|
||||
specifier: ^19
|
||||
version: 19.1.0
|
||||
|
||||
packages/data:
|
||||
dependencies:
|
||||
'@afilmory/builder':
|
||||
@@ -2926,11 +3025,6 @@ packages:
|
||||
zod:
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/container-queries@0.1.1':
|
||||
resolution: {integrity: sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==}
|
||||
peerDependencies:
|
||||
tailwindcss: '>=3.2.0'
|
||||
|
||||
'@tailwindcss/node@4.1.11':
|
||||
resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==}
|
||||
|
||||
@@ -3179,6 +3273,9 @@ packages:
|
||||
'@types/hast@3.0.4':
|
||||
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
|
||||
|
||||
'@types/js-cookie@2.2.7':
|
||||
resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==}
|
||||
|
||||
'@types/json-schema@7.0.15':
|
||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||
|
||||
@@ -3496,6 +3593,9 @@ packages:
|
||||
'@vue/shared@3.5.16':
|
||||
resolution: {integrity: sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==}
|
||||
|
||||
'@xobotyi/scrollbar-width@1.9.5':
|
||||
resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==}
|
||||
|
||||
acorn-jsx@5.3.2:
|
||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||
peerDependencies:
|
||||
@@ -4042,12 +4142,19 @@ packages:
|
||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
css-in-js-utils@3.1.0:
|
||||
resolution: {integrity: sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==}
|
||||
|
||||
css-select@4.3.0:
|
||||
resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
|
||||
|
||||
css-select@5.1.0:
|
||||
resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
|
||||
|
||||
css-tree@1.1.3:
|
||||
resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
|
||||
css-what@6.1.0:
|
||||
resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -4491,6 +4598,9 @@ packages:
|
||||
error-ex@1.3.2:
|
||||
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||
|
||||
error-stack-parser@2.1.4:
|
||||
resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==}
|
||||
|
||||
es-toolkit@1.39.5:
|
||||
resolution: {integrity: sha512-z9V0qU4lx1TBXDNFWfAASWk6RNU6c6+TJBKE+FLIg8u0XJ6Yw58Hi0yX8ftEouj6p1QARRlXLFfHbIli93BdQQ==}
|
||||
|
||||
@@ -4859,10 +4969,16 @@ packages:
|
||||
fast-levenshtein@2.0.6:
|
||||
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
|
||||
|
||||
fast-shallow-equal@1.0.0:
|
||||
resolution: {integrity: sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==}
|
||||
|
||||
fast-xml-parser@4.4.1:
|
||||
resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==}
|
||||
hasBin: true
|
||||
|
||||
fastest-stable-stringify@2.0.2:
|
||||
resolution: {integrity: sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==}
|
||||
|
||||
fastq@1.19.1:
|
||||
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
|
||||
|
||||
@@ -5177,6 +5293,9 @@ packages:
|
||||
resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==}
|
||||
engines: {node: '>=18.18.0'}
|
||||
|
||||
hyphenate-style-name@1.1.0:
|
||||
resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==}
|
||||
|
||||
i18next-browser-languagedetector@8.2.0:
|
||||
resolution: {integrity: sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==}
|
||||
|
||||
@@ -5236,6 +5355,9 @@ packages:
|
||||
inline-style-parser@0.2.4:
|
||||
resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==}
|
||||
|
||||
inline-style-prefixer@7.0.1:
|
||||
resolution: {integrity: sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==}
|
||||
|
||||
internmap@1.0.1:
|
||||
resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==}
|
||||
|
||||
@@ -5367,6 +5489,9 @@ packages:
|
||||
jpeg-js@0.4.4:
|
||||
resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==}
|
||||
|
||||
js-cookie@2.2.1:
|
||||
resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==}
|
||||
|
||||
js-cookie@3.0.5:
|
||||
resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -5700,6 +5825,9 @@ packages:
|
||||
mdast-util-to-string@4.0.0:
|
||||
resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
|
||||
|
||||
mdn-data@2.0.14:
|
||||
resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==}
|
||||
|
||||
meow@13.2.0:
|
||||
resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -5910,6 +6038,12 @@ packages:
|
||||
resolution: {integrity: sha512-kMbrH0EObaKmK3nVRKUIIya1dpASHIEusM13S4V1ViHFuxuNxCo+arxoa6j/dbV22YBGjl7UKJm9QQKJ2Crzhg==}
|
||||
deprecated: See https://github.com/mvdan/sh/issues/1145
|
||||
|
||||
nano-css@5.6.2:
|
||||
resolution: {integrity: sha512-+6bHaC8dSDGALM1HJjOHVXpuastdu2xFoZlC77Jh4cg+33Zcgm+Gxd+1xsnpZK14eyHObSp82+ll5y3SX75liw==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
react-dom: '*'
|
||||
|
||||
nano-spawn@1.0.2:
|
||||
resolution: {integrity: sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg==}
|
||||
engines: {node: '>=20.17'}
|
||||
@@ -6763,6 +6897,9 @@ packages:
|
||||
'@types/react': '>=18'
|
||||
react: '>=18'
|
||||
|
||||
react-masonry@1.0.7:
|
||||
resolution: {integrity: sha512-cKhinTeygGtm+8y7YCTMKXNKtU0toJAcOBD4q7fv+JTc94bj93/xut3iZvjD60lZYek+WGM6en5w8P+63zHN9Q==}
|
||||
|
||||
react-merge-refs@3.0.2:
|
||||
resolution: {integrity: sha512-MSZAfwFfdbEvwkKWP5EI5chuLYnNUxNS7vyS0i1Jp+wtd8J4Ga2ddzhaE68aMol2Z4vCnRM/oGOo1a3V75UPlw==}
|
||||
peerDependencies:
|
||||
@@ -6771,6 +6908,12 @@ packages:
|
||||
react:
|
||||
optional: true
|
||||
|
||||
react-photo-view@1.2.7:
|
||||
resolution: {integrity: sha512-MfOWVPxuibncRLaycZUNxqYU8D9IA+rbGDDaq6GM8RIoGJal592hEJoRAyRSI7ZxyyJNJTLMUWWL3UIXHJJOpw==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
|
||||
react-refresh@0.17.0:
|
||||
resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -6795,6 +6938,9 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
react-responsive-masonry@2.7.1:
|
||||
resolution: {integrity: sha512-Q+u+nOH87PzjqGFd2PgTcmLpHPZnCmUPREHYoNBc8dwJv6fi51p9U6hqwG8g/T8MN86HrFjrU+uQU6yvETU7cA==}
|
||||
|
||||
react-rnd@10.5.2:
|
||||
resolution: {integrity: sha512-0Tm4x7k7pfHf2snewJA8x7Nwgt3LV+58MVEWOVsFjk51eYruFEa6Wy7BNdxt4/lH0wIRsu7Gm3KjSXY2w7YaNw==}
|
||||
peerDependencies:
|
||||
@@ -6841,6 +6987,12 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
react-universal-interface@0.6.2:
|
||||
resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
tslib: '*'
|
||||
|
||||
react-use-measure@2.1.7:
|
||||
resolution: {integrity: sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==}
|
||||
peerDependencies:
|
||||
@@ -6850,6 +7002,12 @@ packages:
|
||||
react-dom:
|
||||
optional: true
|
||||
|
||||
react-use@17.6.0:
|
||||
resolution: {integrity: sha512-OmedEScUMKFfzn1Ir8dBxiLLSOzhKe/dPZwVxcujweSj45aNM7BEGPb9BEVIgVEqEXx6f3/TsXzwIktNgUR02g==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
react-dom: '*'
|
||||
|
||||
react-zoom-pan-pinch@3.7.0:
|
||||
resolution: {integrity: sha512-UmReVZ0TxlKzxSbYiAj+LeGRW8s8LraAFTXRAxzMYnNRgGPsxCudwZKVkjvGmjtx7SW/hZamt69NUmGf4xrkXA==}
|
||||
engines: {node: '>=8', npm: '>=5'}
|
||||
@@ -6857,6 +7015,10 @@ packages:
|
||||
react: '*'
|
||||
react-dom: '*'
|
||||
|
||||
react@18.3.1:
|
||||
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
react@19.1.0:
|
||||
resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -7022,6 +7184,9 @@ packages:
|
||||
roughjs@4.6.6:
|
||||
resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==}
|
||||
|
||||
rtl-css-js@1.16.1:
|
||||
resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==}
|
||||
|
||||
run-parallel@1.2.0:
|
||||
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||
|
||||
@@ -7071,6 +7236,10 @@ packages:
|
||||
set-cookie-parser@2.7.1:
|
||||
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
|
||||
|
||||
set-harmonic-interval@1.0.1:
|
||||
resolution: {integrity: sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g==}
|
||||
engines: {node: '>=6.9'}
|
||||
|
||||
set-value@2.0.1:
|
||||
resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -7143,6 +7312,10 @@ packages:
|
||||
source-map-support@0.5.21:
|
||||
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
|
||||
|
||||
source-map@0.5.6:
|
||||
resolution: {integrity: sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
source-map@0.5.7:
|
||||
resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -7192,6 +7365,18 @@ packages:
|
||||
stable-hash@0.0.5:
|
||||
resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
|
||||
|
||||
stack-generator@2.0.10:
|
||||
resolution: {integrity: sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==}
|
||||
|
||||
stackframe@1.3.4:
|
||||
resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==}
|
||||
|
||||
stacktrace-gps@3.1.2:
|
||||
resolution: {integrity: sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==}
|
||||
|
||||
stacktrace-js@2.0.2:
|
||||
resolution: {integrity: sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==}
|
||||
|
||||
streamsearch@1.1.0:
|
||||
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
@@ -7357,6 +7542,10 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
throttle-debounce@3.0.1:
|
||||
resolution: {integrity: sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
throttle-debounce@5.0.2:
|
||||
resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==}
|
||||
engines: {node: '>=12.22'}
|
||||
@@ -7429,6 +7618,9 @@ packages:
|
||||
resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==}
|
||||
engines: {node: '>=6.10'}
|
||||
|
||||
ts-easing@0.2.0:
|
||||
resolution: {integrity: sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==}
|
||||
|
||||
ts-md5@1.3.1:
|
||||
resolution: {integrity: sha512-DiwiXfwvcTeZ5wCE0z+2A9EseZsztaiZtGrtSaY5JOD7ekPnR/GoIVD5gXZAlK9Na9Kvpo9Waz5rW64WKAWApg==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -11041,10 +11233,6 @@ snapshots:
|
||||
typescript: 5.8.3
|
||||
zod: 3.25.67
|
||||
|
||||
'@tailwindcss/container-queries@0.1.1(tailwindcss@4.1.11)':
|
||||
dependencies:
|
||||
tailwindcss: 4.1.11
|
||||
|
||||
'@tailwindcss/node@4.1.11':
|
||||
dependencies:
|
||||
'@ampproject/remapping': 2.3.0
|
||||
@@ -11318,6 +11506,8 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
|
||||
'@types/js-cookie@2.2.7': {}
|
||||
|
||||
'@types/json-schema@7.0.15': {}
|
||||
|
||||
'@types/katex@0.16.7': {}
|
||||
@@ -11681,6 +11871,8 @@ snapshots:
|
||||
|
||||
'@vue/shared@3.5.16': {}
|
||||
|
||||
'@xobotyi/scrollbar-width@1.9.5': {}
|
||||
|
||||
acorn-jsx@5.3.2(acorn@8.14.1):
|
||||
dependencies:
|
||||
acorn: 8.14.1
|
||||
@@ -12283,6 +12475,10 @@ snapshots:
|
||||
shebang-command: 2.0.0
|
||||
which: 2.0.2
|
||||
|
||||
css-in-js-utils@3.1.0:
|
||||
dependencies:
|
||||
hyphenate-style-name: 1.1.0
|
||||
|
||||
css-select@4.3.0:
|
||||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
@@ -12299,6 +12495,11 @@ snapshots:
|
||||
domutils: 3.2.2
|
||||
nth-check: 2.1.1
|
||||
|
||||
css-tree@1.1.3:
|
||||
dependencies:
|
||||
mdn-data: 2.0.14
|
||||
source-map: 0.6.1
|
||||
|
||||
css-what@6.1.0: {}
|
||||
|
||||
cssesc@3.0.0: {}
|
||||
@@ -12646,6 +12847,10 @@ snapshots:
|
||||
dependencies:
|
||||
is-arrayish: 0.2.1
|
||||
|
||||
error-stack-parser@2.1.4:
|
||||
dependencies:
|
||||
stackframe: 1.3.4
|
||||
|
||||
es-toolkit@1.39.5: {}
|
||||
|
||||
esast-util-from-estree@2.0.0:
|
||||
@@ -13240,10 +13445,14 @@ snapshots:
|
||||
|
||||
fast-levenshtein@2.0.6: {}
|
||||
|
||||
fast-shallow-equal@1.0.0: {}
|
||||
|
||||
fast-xml-parser@4.4.1:
|
||||
dependencies:
|
||||
strnum: 1.1.2
|
||||
|
||||
fastest-stable-stringify@2.0.2: {}
|
||||
|
||||
fastq@1.19.1:
|
||||
dependencies:
|
||||
reusify: 1.1.0
|
||||
@@ -13643,6 +13852,8 @@ snapshots:
|
||||
|
||||
human-signals@8.0.1: {}
|
||||
|
||||
hyphenate-style-name@1.1.0: {}
|
||||
|
||||
i18next-browser-languagedetector@8.2.0:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.27.6
|
||||
@@ -13687,6 +13898,10 @@ snapshots:
|
||||
|
||||
inline-style-parser@0.2.4: {}
|
||||
|
||||
inline-style-prefixer@7.0.1:
|
||||
dependencies:
|
||||
css-in-js-utils: 3.1.0
|
||||
|
||||
internmap@1.0.1: {}
|
||||
|
||||
internmap@2.0.3: {}
|
||||
@@ -13784,6 +13999,8 @@ snapshots:
|
||||
|
||||
jpeg-js@0.4.4: {}
|
||||
|
||||
js-cookie@2.2.1: {}
|
||||
|
||||
js-cookie@3.0.5: {}
|
||||
|
||||
js-tokens@4.0.0: {}
|
||||
@@ -14249,6 +14466,8 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
|
||||
mdn-data@2.0.14: {}
|
||||
|
||||
meow@13.2.0: {}
|
||||
|
||||
merge-value@1.0.0:
|
||||
@@ -14632,6 +14851,19 @@ snapshots:
|
||||
|
||||
mvdan-sh@0.10.1: {}
|
||||
|
||||
nano-css@5.6.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
css-tree: 1.1.3
|
||||
csstype: 3.1.3
|
||||
fastest-stable-stringify: 2.0.2
|
||||
inline-style-prefixer: 7.0.1
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
rtl-css-js: 1.16.1
|
||||
stacktrace-js: 2.0.2
|
||||
stylis: 4.3.6
|
||||
|
||||
nano-spawn@1.0.2: {}
|
||||
|
||||
nanoid@3.3.11: {}
|
||||
@@ -15540,10 +15772,19 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
react-masonry@1.0.7:
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
||||
react-merge-refs@3.0.2(react@19.1.0):
|
||||
optionalDependencies:
|
||||
react: 19.1.0
|
||||
|
||||
react-photo-view@1.2.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
|
||||
react-refresh@0.17.0: {}
|
||||
|
||||
react-remove-scroll-bar@2.3.8(@types/react@19.1.8)(react@19.1.0):
|
||||
@@ -15565,6 +15806,8 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.8
|
||||
|
||||
react-responsive-masonry@2.7.1: {}
|
||||
|
||||
react-rnd@10.5.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
re-resizable: 6.11.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
@@ -15619,17 +15862,45 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.8
|
||||
|
||||
react-universal-interface@0.6.2(react@19.1.0)(tslib@2.8.1):
|
||||
dependencies:
|
||||
react: 19.1.0
|
||||
tslib: 2.8.1
|
||||
|
||||
react-use-measure@2.1.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
react: 19.1.0
|
||||
optionalDependencies:
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
|
||||
react-use@17.6.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
'@types/js-cookie': 2.2.7
|
||||
'@xobotyi/scrollbar-width': 1.9.5
|
||||
copy-to-clipboard: 3.3.3
|
||||
fast-deep-equal: 3.1.3
|
||||
fast-shallow-equal: 1.0.0
|
||||
js-cookie: 2.2.1
|
||||
nano-css: 5.6.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
react-universal-interface: 0.6.2(react@19.1.0)(tslib@2.8.1)
|
||||
resize-observer-polyfill: 1.5.1
|
||||
screenfull: 5.2.0
|
||||
set-harmonic-interval: 1.0.1
|
||||
throttle-debounce: 3.0.1
|
||||
ts-easing: 0.2.0
|
||||
tslib: 2.8.1
|
||||
|
||||
react-zoom-pan-pinch@3.7.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
|
||||
react@18.3.1:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
|
||||
react@19.1.0: {}
|
||||
|
||||
read-cache@1.0.0:
|
||||
@@ -15904,6 +16175,10 @@ snapshots:
|
||||
points-on-curve: 0.2.0
|
||||
points-on-path: 0.2.1
|
||||
|
||||
rtl-css-js@1.16.1:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.27.6
|
||||
|
||||
run-parallel@1.2.0:
|
||||
dependencies:
|
||||
queue-microtask: 1.2.3
|
||||
@@ -15944,6 +16219,8 @@ snapshots:
|
||||
|
||||
set-cookie-parser@2.7.1: {}
|
||||
|
||||
set-harmonic-interval@1.0.1: {}
|
||||
|
||||
set-value@2.0.1:
|
||||
dependencies:
|
||||
extend-shallow: 2.0.1
|
||||
@@ -16048,6 +16325,8 @@ snapshots:
|
||||
buffer-from: 1.1.2
|
||||
source-map: 0.6.1
|
||||
|
||||
source-map@0.5.6: {}
|
||||
|
||||
source-map@0.5.7: {}
|
||||
|
||||
source-map@0.6.1: {}
|
||||
@@ -16084,6 +16363,23 @@ snapshots:
|
||||
|
||||
stable-hash@0.0.5: {}
|
||||
|
||||
stack-generator@2.0.10:
|
||||
dependencies:
|
||||
stackframe: 1.3.4
|
||||
|
||||
stackframe@1.3.4: {}
|
||||
|
||||
stacktrace-gps@3.1.2:
|
||||
dependencies:
|
||||
source-map: 0.5.6
|
||||
stackframe: 1.3.4
|
||||
|
||||
stacktrace-js@2.0.2:
|
||||
dependencies:
|
||||
error-stack-parser: 2.1.4
|
||||
stack-generator: 2.0.10
|
||||
stacktrace-gps: 3.1.2
|
||||
|
||||
streamsearch@1.1.0: {}
|
||||
|
||||
string-argv@0.3.2: {}
|
||||
@@ -16236,6 +16532,8 @@ snapshots:
|
||||
commander: 2.20.3
|
||||
source-map-support: 0.5.21
|
||||
|
||||
throttle-debounce@3.0.1: {}
|
||||
|
||||
throttle-debounce@5.0.2: {}
|
||||
|
||||
thumbhash@0.1.1: {}
|
||||
@@ -16297,6 +16595,8 @@ snapshots:
|
||||
|
||||
ts-dedent@2.2.0: {}
|
||||
|
||||
ts-easing@0.2.0: {}
|
||||
|
||||
ts-md5@1.3.1: {}
|
||||
|
||||
ts-pattern@5.7.1: {}
|
||||
|
||||
@@ -7,3 +7,13 @@ catalog:
|
||||
'@t3-oss/env-core': 0.13.8
|
||||
dotenv-expand: 12.0.2
|
||||
typescript: 5.8.3
|
||||
'tailwind-variants': '1.0.0'
|
||||
'@tailwindcss/postcss': '4.1.11'
|
||||
'@tailwindcss/typography': '0.5.16'
|
||||
'tailwind-scrollbar': '4.0.2'
|
||||
'tailwindcss': '4.1.11'
|
||||
'tailwindcss-animate': '1.0.7'
|
||||
'tailwindcss-safe-area': '0.6.0'
|
||||
'tailwindcss-uikit-colors': '1.0.0-alpha.1'
|
||||
'@egoist/tailwindcss-icons': '1.9.0'
|
||||
'@iconify-json/mingcute': '1.2.3'
|
||||
|
||||
Reference in New Issue
Block a user