This commit is contained in:
Maze Winther 2026-01-21 12:52:20 +01:00
parent e1d82eca09
commit 8500dd770b
123 changed files with 544 additions and 441 deletions

View File

@ -319,106 +319,26 @@ use-element-selection.ts
## apps/web/src/lib
audio-utils.ts
export type CollectedAudioElement = Omit<
AudioElement,
"type" | "mediaId" | "volume" | "id" | "name" | "sourceType" | "sourceU...
export function createAudioContext(): AudioContext
export interface DecodedAudio {
samples: Float32Array
sampleRate: number
}
export function decodeAudioToFloat32({
audioBlob,
browser-utils.ts
export function isTypableDOMElement({
element,
}: {
audioBlob: Blob;
}): Promise<DecodedAudio>
export function collectAudioElements({
tracks,
mediaAssets,
audioContext,
}: {
tracks: TimelineTrack[];
mediaAssets: MediaAsset[];
audioContext: AudioContext;
}): Promise<CollectedAudioElement[]>
export function collectAudioMixSources({
tracks,
mediaAssets,
}: {
tracks: TimelineTrack[];
mediaAssets: MediaAsset[];
}): Promise<AudioMixSource[]>
export function createTimelineAudioBuffer({
tracks,
mediaAssets,
duration,
sampleRate = 44100,
}: {
tracks: TimelineTrack[];
mediaAssets: MediaAsset[];
duration: number;
sampleRate?: number;
}): Promise<AudioBuffer | null>
blog-query.ts
export function getPosts()
export function getTags()
export function getSinglePost({ slug }: { slug: string })
export function getCategories()
export function getAuthors()
export function processHtmlContent({ html }: { html: string }): Promise<string>
caption-utils.ts
export function buildCaptionChunks({
segments,
wordsPerChunk = DEFAULT_WORDS_PER_CAPTION,
minDuration = MIN_CAPTION_DURATION_SECONDS,
}: {
segments: TranscriptionSegment[];
wordsPerChunk?: number;
minDuration?: number;
}): CaptionChunk[]
drag-data.ts
export function setDragData({
dataTransfer,
dragData,
}: {
dataTransfer: DataTransfer;
dragData: TimelineDragData;
}): void
export function getDragData({
dataTransfer,
}: {
dataTransfer: DataTransfer;
}): TimelineDragData | null
export function hasDragData({
dataTransfer,
}: {
dataTransfer: DataTransfer;
element: HTMLElement;
}): boolean
export function clearDragData(): void
editor-utils.ts
export function dimensionToAspectRatio({
width,
height,
}: {
width: number;
height: number;
}): string
date-utils.ts
export function formatDate({ date }: { date: Date }): string
export.ts
export function getExportMimeType({
format,
}: {
format: "mp4" | "webm";
format: ExportFormat;
}): string
export function getExportFileExtension({
format,
}: {
format: "mp4" | "webm";
format: ExportFormat;
}): string
iconify-api.ts
@ -493,22 +413,21 @@ iconify-api.ts
collections: Record<string, IconSet>
): string[]
keyboard-utils.ts
math-utils.ts
export function clamp({
value,
min,
max,
}: {
value: number;
min: number;
max: number;
}): number
platform-utils.ts
export function getPlatformSpecialKey(): string
export function getPlatformAlternateKey(): string
media-utils.ts
export const SUPPORTS_AUDIO: readonly MediaType[]
export function mediaSupportsAudio({
media,
}: {
media: MediaAsset | null | undefined;
}): boolean
export const getMediaTypeFromFile = ({ file }: { file: File }): MediaType | null => ...
rate-limit.ts
export const baseRateLimit
export function checkRateLimit({ request }: { request: Request })
export function isAppleDevice(): boolean
scene-utils.ts
export function getMainScene({ scenes }: { scenes: TScene[] }): TScene | null
@ -550,6 +469,10 @@ scene-utils.ts
updates: Partial<TScene>;
}): TScene[]
string-utils.ts
export function capitalizeFirstLetter({ string }: { string: string })
export function uppercase({ string }: { string: string })
time-utils.ts
export function roundToFrame({
time,
@ -612,28 +535,6 @@ time-utils.ts
fps: number;
}): number
utils.ts
export function cn(...inputs: ClassValue[]): string
export function formatDate({ date }: { date: Date }): string
export function capitalizeFirstLetter({ string }: { string: string })
export function uppercase({ string }: { string: string })
export function generateUUID(): string
export function isTypableDOMElement({
element,
}: {
element: HTMLElement;
}): boolean
export function isAppleDevice(): boolean
export function clamp({
value,
min,
max,
}: {
value: number;
min: number;
max: number;
}): number
## apps/web/src/lib/actions
definitions.ts
@ -698,6 +599,16 @@ server.ts
export const auth
export type Auth = typeof auth
## apps/web/src/lib/blog
query.ts
export function getPosts()
export function getTags()
export function getSinglePost({ slug }: { slug: string })
export function getCategories()
export function getAuthors()
export function processHtmlContent({ html }: { html: string }): Promise<string>
## apps/web/src/lib/db
index.ts
@ -739,6 +650,15 @@ parser.ts
## apps/web/src/lib/media
media-utils.ts
export const SUPPORTS_AUDIO: readonly MediaType[]
export function mediaSupportsAudio({
media,
}: {
media: MediaAsset | null | undefined;
}): boolean
export const getMediaTypeFromFile = ({ file }: { file: File }): MediaType | null => ...
mediabunny.ts
export const initFFmpeg = (): Promise<FFmpeg> => ...
export function getVideoInfo({
@ -1006,6 +926,161 @@ zoom-utils.ts
containerWidth: number | null | undefined;
}): number
## apps/web/src/lib/utils
audio.ts
export type CollectedAudioElement = Omit<
AudioElement,
"type" | "mediaId" | "volume" | "id" | "name" | "sourceType" | "sourceU...
export function createAudioContext(): AudioContext
export interface DecodedAudio {
samples: Float32Array
sampleRate: number
}
export function decodeAudioToFloat32({
audioBlob,
}: {
audioBlob: Blob;
}): Promise<DecodedAudio>
export function collectAudioElements({
tracks,
mediaAssets,
audioContext,
}: {
tracks: TimelineTrack[];
mediaAssets: MediaAsset[];
audioContext: AudioContext;
}): Promise<CollectedAudioElement[]>
export function collectAudioMixSources({
tracks,
mediaAssets,
}: {
tracks: TimelineTrack[];
mediaAssets: MediaAsset[];
}): Promise<AudioMixSource[]>
export function createTimelineAudioBuffer({
tracks,
mediaAssets,
duration,
sampleRate = 44100,
}: {
tracks: TimelineTrack[];
mediaAssets: MediaAsset[];
duration: number;
sampleRate?: number;
}): Promise<AudioBuffer | null>
blog-query.ts
export function getPosts()
export function getTags()
export function getSinglePost({ slug }: { slug: string })
export function getCategories()
export function getAuthors()
export function processHtmlContent({ html }: { html: string }): Promise<string>
browser.ts
export function isTypableDOMElement({
element,
}: {
element: HTMLElement;
}): boolean
date.ts
export function formatDate({ date }: { date: Date }): string
editor.ts
export function dimensionToAspectRatio({
width,
height,
}: {
width: number;
height: number;
}): string
id.ts
export function generateUUID(): string
math.ts
export function clamp({
value,
min,
max,
}: {
value: number;
min: number;
max: number;
}): number
platform.ts
export function getPlatformSpecialKey(): string
export function getPlatformAlternateKey(): string
export function isAppleDevice(): boolean
time.ts
export function roundToFrame({
time,
fps,
}: {
time: number;
fps: number;
}): number
export function formatTimeCode({
timeInSeconds,
format = "HH:MM:SS:CS",
fps,
}: {
timeInSeconds: number;
format?: TTimeCode;
fps?: number;
}): string
export function parseTimeCode({
timeCode,
format = "HH:MM:SS:CS",
fps,
}: {
timeCode: string;
format?: TTimeCode;
fps: number;
}): number | null
export function guessTimeCodeFormat({
timeCode,
}: {
timeCode: string;
}): TTimeCode | null
export function timeToFrame({
time,
fps,
}: {
time: number;
fps: number;
}): number
export function frameToTime({
frame,
fps,
}: {
frame: number;
fps: number;
}): number
export function snapTimeToFrame({
time,
fps,
}: {
time: number;
fps: number;
}): number
export function getSnappedSeekTime({
rawTime,
duration,
fps,
}: {
rawTime: number;
duration: number;
fps: number;
}): number
ui.ts
export function cn(...inputs: ClassValue[]): string
## apps/web/src/services/media
video-cache.ts
@ -1584,20 +1659,19 @@ transcription.ts
segments: TranscriptionSegment[]
language: string
}
export type TranscriptionStatus = | "idle"
| "loading-model"
| "ready"
| "transcribing"
| "complete"
| "er...
export type TranscriptionStatus = | "idle"
| "loading-model"
| "transcribing"
| "complete"
| "error"
export interface TranscriptionProgress {
status: TranscriptionStatus
progress: number
message?: string
}
export type TranscriptionModelId = | "whisper-tiny"
| "whisper-small"
| "whisper-medium"
export type TranscriptionModelId = | "whisper-tiny"
| "whisper-small"
| "whisper-medium"
| "whisper-large-v3-turbo"
export interface TranscriptionModel {
id: TranscriptionModelId
@ -1611,6 +1685,36 @@ transcription.ts
duration: number
}
## apps/web/src/utils
geometry.ts
export function dimensionToAspectRatio({
width,
height,
}: {
width: number;
height: number;
}): string
math.ts
export function clamp({
value,
min,
max,
}: {
value: number;
min: number;
max: number;
}): number
platform.ts
export function getPlatformSpecialKey(): string
export function getPlatformAlternateKey(): string
export function isAppleDevice(): boolean
ui.ts
export function cn(...inputs: ClassValue[]): string
## packages/ui/src/icons
index.tsx

View File

@ -93,14 +93,14 @@ function buildSortParameter({ query, sort }: { query?: string; sort: string }) {
return sort === "score" ? "score" : `${sort}_desc`;
}
function applyEffectsFilters({
params,
min_rating,
commercial_only
}: {
params: URLSearchParams;
min_rating: number;
commercial_only: boolean;
function applyEffectsFilters({
params,
min_rating,
commercial_only
}: {
params: URLSearchParams;
min_rating: number;
commercial_only: boolean;
}) {
params.append("filter", "duration:[* TO 30.0]");
params.append("filter", `avg_rating:[${min_rating} TO *]`);

View File

@ -1,6 +1,6 @@
import { Header } from "@/components/header";
import { Footer } from "@/components/footer";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
interface BasePageProps {
children: React.ReactNode;

View File

@ -1,7 +1,7 @@
import { BasePage } from "@/app/base-page";
import Prose from "@/components/ui/prose";
import { Separator } from "@/components/ui/separator";
import { getPosts, getSinglePost, processHtmlContent } from "@/lib/blog-query";
import { getPosts, getSinglePost, processHtmlContent } from "@/lib/blog/query";
import { Post, Author } from "@/types/blog";
import { Metadata } from "next";
import Image from "next/image";

View File

@ -2,7 +2,7 @@ import { Metadata } from "next";
import { BasePage } from "@/app/base-page";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import Link from "next/link";
import { getPosts } from "@/lib/blog-query";
import { getPosts } from "@/lib/blog/query";
import { Post, Author } from "@/types/blog";
import { Separator } from "@/components/ui/separator";

View File

@ -40,7 +40,7 @@ import { MigrationDialog } from "@/components/editor/migration-dialog";
import type { TProjectMetadata } from "@/types/project";
import { toast } from "sonner";
import { useEditor } from "@/hooks/use-editor";
import { formatDate } from "@/lib/utils";
import { formatDate } from "@/utils/date";
export default function ProjectsPage() {
const [isSelectionMode, setIsSelectionMode] = useState(false);
@ -419,14 +419,12 @@ function ProjectCard({
const cardContent = (
<Card
className={`bg-background overflow-hidden border-none p-0 transition-all ${
isSelectionMode && isSelected ? "ring-primary ring-2" : ""
}`}
className={`bg-background overflow-hidden border-none p-0 transition-all ${isSelectionMode && isSelected ? "ring-primary ring-2" : ""
}`}
>
<div
className={`bg-muted relative aspect-square transition-opacity ${
isDropdownOpen ? "opacity-65" : "opacity-100 group-hover:opacity-65"
}`}
className={`bg-muted relative aspect-square transition-opacity ${isDropdownOpen ? "opacity-65" : "opacity-100 group-hover:opacity-65"
}`}
>
{isSelectionMode && (
<div className="absolute left-3 top-3 z-10">
@ -477,11 +475,10 @@ function ProjectCard({
aria-label="project options"
variant="text"
size="sm"
className={`ml-2 size-6 shrink-0 p-0 transition-all ${
isDropdownOpen
? "opacity-100"
: "opacity-0 group-hover:opacity-100"
}`}
className={`ml-2 size-6 shrink-0 p-0 transition-all ${isDropdownOpen
? "opacity-100"
: "opacity-0 group-hover:opacity-100"
}`}
onClick={(event) => event.preventDefault()}
>
<MoreHorizontal aria-hidden="true" />

View File

@ -1,7 +1,7 @@
import { Metadata } from "next";
import { Badge } from "@/components/ui/badge";
import { ReactMarkdownWrapper } from "@/components/ui/react-markdown-wrapper";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import { BasePage } from "@/app/base-page";
import { GitHubContributeSection } from "@/components/gitHub-contribute-section";

View File

@ -1,5 +1,5 @@
import { Feed } from "feed";
import { getPosts } from "@/lib/blog-query";
import { getPosts } from "@/lib/blog/query";
import { SITE_INFO, SITE_URL } from "@/constants/site-constants";
export async function GET() {
@ -14,9 +14,8 @@ export async function GET() {
language: "en",
image: `${SITE_INFO.openGraphImage}`,
favicon: `${SITE_INFO.favicon}`,
copyright: `All rights reserved ${new Date().getFullYear()}, ${
SITE_INFO.title
}`,
copyright: `All rights reserved ${new Date().getFullYear()}, ${SITE_INFO.title
}`,
});
for (const post of posts) {

View File

@ -1,5 +1,5 @@
import { SITE_URL } from "@/constants/site-constants";
import { getPosts } from "@/lib/blog-query";
import { getPosts } from "@/lib/blog/query";
import type { MetadataRoute } from "next";
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {

View File

@ -1,6 +1,6 @@
"use client";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import {
TAB_KEYS,
tabs,

View File

@ -10,8 +10,8 @@ import { LANGUAGES } from "@/constants/captions-constants";
import { Loader2 } from "lucide-react";
import type { TranscriptionProgress } from "@/types/transcription";
import { transcriptionService } from "@/services/transcription";
import { decodeAudioToFloat32 } from "@/lib/audio-utils";
import { buildCaptionChunks } from "@/lib/caption-utils";
import { decodeAudioToFloat32 } from "@/lib/media/audio";
import { buildCaptionChunks } from "@/lib/utils/caption-utils";
export function Captions() {
const [selectedLanguage, setSelectedLanguage] = useState("auto");

View File

@ -17,7 +17,7 @@ import { useEditor } from "@/hooks/use-editor";
import { useFileUpload } from "@/hooks/use-file-upload";
import { useRevealItem } from "@/hooks/use-reveal-item";
import { processMediaAssets } from "@/lib/media/processing";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
import type { MediaAsset } from "@/types/assets";
import type { CreateTimelineElement } from "@/types/timeline";

View File

@ -21,9 +21,9 @@ import {
DEFAULT_COLOR,
} from "@/constants/project-constants";
import { useEditorStore } from "@/stores/editor-store";
import { dimensionToAspectRatio } from "@/lib/editor-utils";
import { dimensionToAspectRatio } from "@/utils/geometry";
import Image from "next/image";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import { colors } from "@/data/colors/solid";
import { patternCraftGradients } from "@/data/colors/pattern-craft";
import { PipetteIcon } from "lucide-react";

View File

@ -31,7 +31,7 @@ import {
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import { useInfiniteScroll } from "@/hooks/use-infinite-scroll";
export function SoundsView() {
@ -547,11 +547,10 @@ function AudioItem({
<Button
variant="text"
size="icon"
className={`hover:text-foreground !opacity-100 w-auto ${
isSaved
? "text-red-500 hover:text-red-600"
: "text-muted-foreground"
}`}
className={`hover:text-foreground !opacity-100 w-auto ${isSaved
? "text-red-500 hover:text-red-600"
: "text-muted-foreground"
}`}
onClick={handleSaveClick}
title={isSaved ? "Remove from saved" : "Save sound"}
>

View File

@ -31,7 +31,7 @@ import {
ICONIFY_HOSTS,
POPULAR_COLLECTIONS,
} from "@/lib/iconify-api";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import Image from "next/image";
import { DraggableItem } from "@/components/ui/draggable-item";
import { InputWithBack } from "@/components/ui/input-with-back";

View File

@ -8,8 +8,8 @@ import { Label } from "../ui/label";
import { RadioGroup, RadioGroupItem } from "../ui/radio-group";
import { Progress } from "../ui/progress";
import { Checkbox } from "../ui/checkbox";
import { cn } from "@/lib/utils";
import { getExportMimeType, getExportFileExtension } from "@/lib/export";
import { cn } from "@/utils/ui";
import { getExportMimeType, getExportFileExtension } from "@/utils/export";
import { Check, Copy, Download, RotateCcw, X } from "lucide-react";
import {
EXPORT_FORMAT_VALUES,

View File

@ -1,7 +1,7 @@
import { ScrollArea } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
interface PanelBaseViewProps {
children?: React.ReactNode;

View File

@ -1,4 +1,4 @@
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import { ChevronDown } from "lucide-react";
import { useState } from "react";

View File

@ -18,7 +18,9 @@ import {
PropertyItemValue,
} from "./property-item";
import { ColorPicker } from "@/components/ui/color-picker";
import { cn, capitalizeFirstLetter, clamp, uppercase } from "@/lib/utils";
import { cn } from "@/utils/ui";
import { capitalizeFirstLetter, uppercase } from "@/utils/string-utils";
import { clamp } from "@/utils/math";
import { Grid2x2 } from "lucide-react";
import {
Tooltip,
@ -296,8 +298,9 @@ export function TextProperties({
<PropertyItemLabel>Color</PropertyItemLabel>
<PropertyItemValue>
<ColorPicker
value={uppercase({ string:
(element.color || "FFFFFF").replace("#", "")
value={uppercase({
string:
(element.color || "FFFFFF").replace("#", "")
})}
onChange={(color) => {
editor.timeline.updateTextElement({
@ -351,9 +354,9 @@ export function TextProperties({
element.backgroundColor === "transparent"
? lastSelectedColor.current.replace("#", "")
: (element.backgroundColor).replace(
"#",
"",
),
"#",
"",
),
})}
onChange={(color) => handleColorChange({ color: `#${color}` })}
containerRef={containerRef}
@ -380,7 +383,7 @@ export function TextProperties({
className={cn(
"text-foreground",
element.backgroundColor === "transparent" &&
"text-primary",
"text-primary",
)}
/>
</Button>

View File

@ -10,7 +10,7 @@ import {
} from "@/components/ui/sheet";
import { Button } from "@/components/ui/button";
import { Check, ListCheck, Trash2 } from "lucide-react";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import { useState } from "react";
import {
Dialog,
@ -21,7 +21,7 @@ import {
DialogFooter,
DialogTrigger,
} from "@/components/ui/dialog";
import { canDeleteScene, getMainScene } from "@/lib/scene-utils";
import { canDeleteScene, getMainScene } from "@/lib/scenes";
import { toast } from "sonner";
import { useEditor } from "@/hooks/use-editor";
@ -147,11 +147,11 @@ export function ScenesView({ children }: { children: React.ReactNode }) {
className={cn(
"w-full justify-between font-normal",
currentScene?.id === scene.id &&
!isSelectMode &&
"border-primary !text-primary",
!isSelectMode &&
"border-primary !text-primary",
isSelectMode &&
selectedScenes.has(scene.id) &&
"bg-accent border-foreground/30",
selectedScenes.has(scene.id) &&
"bg-accent border-foreground/30",
)}
onClick={() => handleSceneSwitch(scene.id)}
>
@ -159,8 +159,8 @@ export function ScenesView({ children }: { children: React.ReactNode }) {
<div className="flex items-center gap-2">
{((isSelectMode && selectedScenes.has(scene.id)) ||
(!isSelectMode && currentScene?.id === scene.id)) && (
<Check className="h-4 w-4" />
)}
<Check className="h-4 w-4" />
)}
</div>
</Button>
))}

View File

@ -38,7 +38,7 @@ import type {
ElementDragState,
} from "@/types/timeline";
import { MediaAsset } from "@/types/assets";
import { mediaSupportsAudio } from "@/lib/media-utils";
import { mediaSupportsAudio } from "@/lib/media/media-utils";
import { type TAction, invokeAction } from "@/lib/actions";
import { useElementSelection } from "@/hooks/timeline/element/use-element-selection";

View File

@ -31,12 +31,12 @@ import {
SplitButtonSeparator,
} from "@/components/ui/split-button";
import { Slider } from "@/components/ui/slider";
import { formatTimeCode } from "@/lib/time-utils";
import { formatTimeCode } from "@/lib/time";
import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
import { EditableTimecode } from "@/components/ui/editable-timecode";
import { ScenesView } from "../scenes-view";
import { type TAction, invokeAction } from "@/lib/actions";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import { useTimelineStore } from "@/stores/timeline-store";
export function TimelineToolbar({

View File

@ -9,7 +9,7 @@ import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
import { useEdgeAutoScroll } from "@/hooks/timeline/use-edge-auto-scroll";
import { ElementDragState } from "@/types/timeline";
import { useEditor } from "@/hooks/use-editor";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
interface TimelineTrackContentProps {
track: TimelineTrack;

View File

@ -3,7 +3,7 @@ import { RiDiscordFill, RiTwitterXLine } from "react-icons/ri";
import { FaGithub } from "react-icons/fa6";
import Image from "next/image";
import { DEFAULT_LOGO_URL, SOCIAL_LINKS } from "@/constants/site-constants";
import { capitalizeFirstLetter } from "@/lib/utils";
import { capitalizeFirstLetter } from "@/utils/string-utils";
type Category = "resources" | "company";

View File

@ -8,7 +8,7 @@ import { ArrowRight } from "lucide-react";
import Image from "next/image";
import { ThemeToggle } from "./theme-toggle";
import { GithubIcon, MenuIcon } from "@opencut/ui/icons";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import { DEFAULT_LOGO_URL, SOCIAL_LINKS } from "@/constants/site-constants";
export function Header() {

View File

@ -1,6 +1,6 @@
import { useState, useRef, useEffect } from "react";
import { ChevronDown, Globe } from "lucide-react";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import { motion } from "motion/react";
import ReactCountryFlag from "react-country-flag";

View File

@ -3,7 +3,7 @@
import { Button } from "./ui/button";
import { Sun } from "lucide-react";
import { useTheme } from "next-themes";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
interface ThemeToggleProps {
className?: string;

View File

@ -4,7 +4,7 @@ import * as React from "react";
import { Accordion as AccordionPrimitive } from "radix-ui";
import { ChevronDown } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Accordion = AccordionPrimitive.Root;

View File

@ -3,7 +3,7 @@
import * as React from "react";
import { AlertDialog as AlertDialogPrimitive } from "radix-ui";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
import { buttonVariants } from "./button";
const AlertDialog = AlertDialogPrimitive.Root;

View File

@ -1,7 +1,7 @@
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const alertVariants = cva(
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",

View File

@ -3,7 +3,7 @@
import * as React from "react";
import { Avatar as AvatarPrimitive } from "radix-ui";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Avatar = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Root>,

View File

@ -1,7 +1,7 @@
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const badgeVariants = cva(
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2",
@ -25,7 +25,7 @@ const badgeVariants = cva(
export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}
VariantProps<typeof badgeVariants> { }
function Badge({ className, variant, ...props }: BadgeProps) {
return (

View File

@ -2,7 +2,7 @@ import * as React from "react";
import { Slot as SlotPrimitive } from "radix-ui";
import { ChevronRight, MoreHorizontal } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Breadcrumb = React.forwardRef<
HTMLElement,

View File

@ -2,7 +2,7 @@ import * as React from "react";
import { Slot as SlotPrimitive } from "radix-ui";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const buttonVariants = cva(
"inline-flex items-center cursor-pointer justify-center gap-2 whitespace-nowrap rounded-full text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
@ -42,7 +42,7 @@ const buttonVariants = cva(
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}

View File

@ -4,7 +4,7 @@ import * as React from "react";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { DayPicker } from "react-day-picker";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
import { buttonVariants } from "./button";
export type CalendarProps = React.ComponentProps<typeof DayPicker>;

View File

@ -1,6 +1,6 @@
import * as React from "react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Card = React.forwardRef<
HTMLDivElement,

View File

@ -6,7 +6,7 @@ import useEmblaCarousel, {
} from "embla-carousel-react";
import { ArrowLeft, ArrowRight } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
import { Button } from "./button";
type CarouselApi = UseEmblaCarouselType[1];

View File

@ -8,7 +8,7 @@ import {
ValueType,
} from "recharts/types/component/DefaultTooltipContent";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
// Format: { THEME_NAME: CSS_SELECTOR }
const THEMES = { light: "", dark: ".dark" } as const;
@ -89,13 +89,13 @@ const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
([theme, prefix]) => `
${prefix} [data-chart=${id}] {
${colorConfig
.map(([key, itemConfig]) => {
const color =
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
itemConfig.color;
return color ? ` --color-${key}: ${color};` : null;
})
.join("\n")}
.map(([key, itemConfig]) => {
const color =
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
itemConfig.color;
return color ? ` --color-${key}: ${color};` : null;
})
.join("\n")}
}
`
)
@ -110,13 +110,13 @@ const ChartTooltip = RechartsPrimitive.Tooltip;
const ChartTooltipContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
React.ComponentProps<"div"> & {
hideLabel?: boolean;
hideIndicator?: boolean;
indicator?: "line" | "dot" | "dashed";
nameKey?: string;
labelKey?: string;
}
React.ComponentProps<"div"> & {
hideLabel?: boolean;
hideIndicator?: boolean;
indicator?: "line" | "dot" | "dashed";
nameKey?: string;
labelKey?: string;
}
>(
(
{
@ -266,10 +266,10 @@ const ChartLegend = RechartsPrimitive.Legend;
const ChartLegendContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> &
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
hideIcon?: boolean;
nameKey?: string;
}
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
hideIcon?: boolean;
nameKey?: string;
}
>(
(
{ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
@ -333,8 +333,8 @@ function getPayloadConfigFromPayload(
const payloadPayload =
"payload" in payload &&
typeof payload.payload === "object" &&
payload.payload !== null
typeof payload.payload === "object" &&
payload.payload !== null
? payload.payload
: undefined;

View File

@ -4,7 +4,7 @@ import * as React from "react";
import { Checkbox as CheckboxPrimitive } from "radix-ui";
import { Check } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>,

View File

@ -1,6 +1,6 @@
import * as React from "react";
import { createPortal } from "react-dom";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
import { Input } from "./input";
interface ColorPickerProps {
@ -321,9 +321,8 @@ const ColorCircle = ({
color: string;
}) => (
<div
className={`absolute border-3 border-white rounded-full shadow-lg pointer-events-none ${
size === "sm" ? "size-3" : "size-4"
}`}
className={`absolute border-3 border-white rounded-full shadow-lg pointer-events-none ${size === "sm" ? "size-3" : "size-4"
}`}
style={{
left: position.left,
top: position.top,

View File

@ -4,7 +4,7 @@ import * as React from "react";
import { DialogProps } from "@radix-ui/react-dialog";
import { Command as CommandPrimitive } from "cmdk";
import { Search } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
import { Dialog, DialogContent } from "./dialog";
const Command = React.forwardRef<

View File

@ -5,7 +5,7 @@ import { ContextMenu as ContextMenuPrimitive } from "radix-ui";
import { Check, ChevronRight, Circle } from "lucide-react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const ContextMenu = ContextMenuPrimitive.Root;

View File

@ -4,7 +4,7 @@ import * as React from "react";
import { Dialog as DialogPrimitive } from "radix-ui";
import { X } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
import { ScrollArea } from "./scroll-area";
const Dialog = DialogPrimitive.Root;

View File

@ -10,7 +10,7 @@ import {
import { ReactNode, useState, useRef, useEffect } from "react";
import { createPortal } from "react-dom";
import { Plus } from "lucide-react";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import { useEditor } from "@/hooks/use-editor";
import { clearDragData, setDragData } from "@/lib/drag-data";
import type { TimelineDragData } from "@/types/drag";

View File

@ -3,7 +3,7 @@
import * as React from "react";
import { Drawer as DrawerPrimitive } from "vaul";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Drawer = ({
shouldScaleBackground = true,

View File

@ -5,7 +5,7 @@ import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
import { Check, ChevronRight, Circle } from "lucide-react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const DropdownMenu = DropdownMenuPrimitive.Root;

View File

@ -1,9 +1,9 @@
"use client";
import { useState, useRef, useEffect } from "react";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import { TTimeCode } from "@/types/time";
import { formatTimeCode, parseTimeCode } from "@/lib/time-utils";
import { formatTimeCode, parseTimeCode } from "@/lib/time";
interface EditableTimecodeProps {
time: number;

View File

@ -12,7 +12,7 @@ import {
useFormContext,
} from "react-hook-form";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
import { Label } from "./label";
const Form = FormProvider;

View File

@ -3,7 +3,7 @@
import * as React from "react";
import { HoverCard as HoverCardPrimitive } from "radix-ui";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const HoverCard = HoverCardPrimitive.Root;

View File

@ -4,7 +4,7 @@ import * as React from "react";
import { OTPInput, OTPInputContext } from "input-otp";
import { Minus } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const InputOTP = React.forwardRef<
React.ElementRef<typeof OTPInput>,

View File

@ -1,7 +1,7 @@
"use client";
import { Eye, EyeOff, X } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
import { Button } from "./button";
import { forwardRef, ComponentProps } from "react";
import { useState } from "react";

View File

@ -4,7 +4,7 @@ import * as React from "react";
import { Label as LabelPrimitive } from "radix-ui";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
@ -13,7 +13,7 @@ const labelVariants = cva(
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
VariantProps<typeof labelVariants>
VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root
ref={ref}

View File

@ -4,7 +4,7 @@ import * as React from "react";
import { Menubar as MenubarPrimitive } from "radix-ui";
import { Check, ChevronRight, Circle } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const MenubarMenu = MenubarPrimitive.Menu;

View File

@ -3,7 +3,7 @@ import { NavigationMenu as NavigationMenuPrimitive } from "radix-ui";
import { cva } from "class-variance-authority";
import { ChevronDown } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const NavigationMenu = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Root>,

View File

@ -1,7 +1,7 @@
import * as React from "react";
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
import { ButtonProps, buttonVariants } from "./button";
const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (

View File

@ -15,7 +15,7 @@ import {
import { Input } from "./input";
import { Popover, PopoverContent, PopoverTrigger } from "./popover";
import { ScrollArea } from "./scroll-area";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
type PhoneInputProps = Omit<
React.ComponentProps<"input">,

View File

@ -3,7 +3,7 @@
import * as React from "react";
import { Popover as PopoverPrimitive } from "radix-ui";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Popover = PopoverPrimitive.Root;

View File

@ -3,7 +3,7 @@
import * as React from "react";
import { Progress as ProgressPrimitive } from "radix-ui";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Progress = React.forwardRef<
React.ElementRef<typeof ProgressPrimitive.Root>,

View File

@ -1,4 +1,4 @@
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
import type React from "react";
type ProseProps = React.HTMLAttributes<HTMLElement> & {

View File

@ -4,7 +4,7 @@ import * as React from "react";
import { RadioGroup as RadioGroupPrimitive } from "radix-ui";
import { Circle } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const RadioGroup = React.forwardRef<
React.ElementRef<typeof RadioGroupPrimitive.Root>,

View File

@ -1,5 +1,5 @@
import ReactMarkdown from "react-markdown";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
export function ReactMarkdownWrapper({ children }: { children: string }) {
return (

View File

@ -2,7 +2,7 @@
import * as ResizablePrimitive from "react-resizable-panels";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const ResizablePanelGroup = ({
className,

View File

@ -1,5 +1,5 @@
import * as React from "react";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
const ScrollArea = React.forwardRef<
HTMLDivElement,

View File

@ -5,7 +5,7 @@ import { Select as SelectPrimitive } from "radix-ui";
import { Check, ChevronDown, ChevronUp } from "lucide-react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Select = SelectPrimitive.Root;
@ -93,7 +93,7 @@ const SelectContent = React.forwardRef<
className={cn(
"relative z-50 max-h-96 min-w-32 overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className
)}
position={position}
@ -108,7 +108,7 @@ const SelectContent = React.forwardRef<
className={cn(
"p-1",
position === "popper" &&
"h-(--radix-select-trigger-height) w-full min-w-(--radix-select-trigger-width)"
"h-(--radix-select-trigger-height) w-full min-w-(--radix-select-trigger-width)"
)}
>
{children}

View File

@ -3,7 +3,7 @@
import * as React from "react";
import * as SeparatorPrimitive from "@radix-ui/react-separator";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>,

View File

@ -5,7 +5,7 @@ import { Dialog as SheetPrimitive } from "radix-ui";
import { cva, type VariantProps } from "class-variance-authority";
import { X } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Sheet = SheetPrimitive.Root;
@ -51,7 +51,7 @@ const sheetVariants = cva(
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
VariantProps<typeof sheetVariants> { }
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,

View File

@ -1,4 +1,4 @@
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
function Skeleton({
className,

View File

@ -3,7 +3,7 @@
import * as React from "react";
import { Slider as SliderPrimitive } from "radix-ui";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Slider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,

View File

@ -1,7 +1,7 @@
import { Button, ButtonProps } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import { ReactNode, forwardRef } from "react";
import { cn } from "@/lib/utils";
import { cn } from "@/utils/ui";
interface SplitButtonProps {
children: ReactNode;

View File

@ -3,7 +3,7 @@
import * as React from "react";
import { Switch as SwitchPrimitives } from "radix-ui";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Switch = React.forwardRef<
React.ElementRef<typeof SwitchPrimitives.Root>,

View File

@ -1,6 +1,6 @@
import * as React from "react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Table = React.forwardRef<
HTMLTableElement,

View File

@ -3,7 +3,7 @@
import * as React from "react";
import { Tabs as TabsPrimitive } from "radix-ui";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Tabs = TabsPrimitive.Root;

View File

@ -1,6 +1,6 @@
import * as React from "react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const Textarea = React.forwardRef<
HTMLTextAreaElement,

View File

@ -5,7 +5,7 @@ import { Toast as ToastPrimitives } from "radix-ui";
import { cva, type VariantProps } from "class-variance-authority";
import { X } from "lucide-react";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const ToastProvider = ToastPrimitives.Provider;
@ -43,7 +43,7 @@ const toastVariants = cva(
const Toast = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
VariantProps<typeof toastVariants>
VariantProps<typeof toastVariants>
>(({ className, variant, ...props }, ref) => {
return (
<ToastPrimitives.Root

View File

@ -4,7 +4,7 @@ import * as React from "react";
import { ToggleGroup as ToggleGroupPrimitive } from "radix-ui";
import { type VariantProps } from "class-variance-authority";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
import { toggleVariants } from "./toggle";
const ToggleGroupContext = React.createContext<
@ -17,7 +17,7 @@ const ToggleGroupContext = React.createContext<
const ToggleGroup = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
VariantProps<typeof toggleVariants>
VariantProps<typeof toggleVariants>
>(({ className, variant, size, children, ...props }, ref) => (
<ToggleGroupPrimitive.Root
ref={ref}
@ -35,7 +35,7 @@ ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
const ToggleGroupItem = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
VariantProps<typeof toggleVariants>
VariantProps<typeof toggleVariants>
>(({ className, children, variant, size, ...props }, ref) => {
const context = React.useContext(ToggleGroupContext);

View File

@ -4,7 +4,7 @@ import * as React from "react";
import { Toggle as TogglePrimitive } from "radix-ui";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "../../lib/utils";
import { cn } from "@/utils/ui";
const toggleVariants = cva(
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
@ -31,7 +31,7 @@ const toggleVariants = cva(
const Toggle = React.forwardRef<
React.ElementRef<typeof TogglePrimitive.Root>,
React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
VariantProps<typeof toggleVariants>
VariantProps<typeof toggleVariants>
>(({ className, variant, size, ...props }, ref) => (
<TogglePrimitive.Root
ref={ref}

View File

@ -2,7 +2,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
import { Tooltip as TooltipPrimitive } from 'radix-ui';
import * as React from 'react';
import { cn } from '@/lib/utils';
import { cn } from '@/utils/ui';
const TooltipProvider = TooltipPrimitive.Provider;
@ -15,7 +15,7 @@ const tooltipVariants = cva(
{
variants: {
variant: {
default: 'bg-popover text-popover-foreground border px-3 py-1.5',
default: 'bg-popover text-popover-foreground border px-3 py-1.5',
destructive:
'bg-destructive/10 text-destructive dark:bg-destructive/20 border-destructive [border-width:0.5px]',
outline: 'border-border',
@ -40,7 +40,7 @@ const tooltipVariants = cva(
interface TooltipContentProps
extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>,
VariantProps<typeof tooltipVariants> {}
VariantProps<typeof tooltipVariants> { }
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,

View File

@ -1,7 +1,7 @@
import type { EditorCore } from "@/core";
import type { MediaAsset } from "@/types/assets";
import { storageService } from "@/services/storage/storage-service";
import { generateUUID } from "@/lib/utils";
import { generateUUID } from "@/utils/id";
import { videoCache } from "@/services/media/video-cache";
import { hasMediaId } from "@/lib/timeline/element-utils";

View File

@ -8,14 +8,14 @@ import type { ExportOptions, ExportResult } from "@/types/export";
import type { TimelineElement } from "@/types/timeline";
import { storageService } from "@/services/storage/storage-service";
import { toast } from "sonner";
import { generateUUID } from "@/lib/utils";
import { generateUUID } from "@/utils/id";
import { UpdateProjectSettingsCommand } from "@/lib/commands/project";
import {
DEFAULT_FPS,
DEFAULT_CANVAS_SIZE,
DEFAULT_COLOR,
} from "@/constants/project-constants";
import { buildDefaultScene } from "@/lib/scene-utils";
import { buildDefaultScene } from "@/lib/scenes";
import { generateThumbnail } from "@/lib/media/processing";
import {
CURRENT_STORAGE_VERSION,

View File

@ -3,13 +3,13 @@ import type { RootNode } from "@/services/renderer/nodes/root-node";
import type { ExportOptions, ExportResult } from "@/types/export";
import { SceneExporter } from "@/services/renderer/scene-exporter";
import { buildScene } from "@/services/renderer/scene-builder";
import { createTimelineAudioBuffer } from "@/lib/audio-utils";
import { createTimelineAudioBuffer } from "@/lib/media/audio";
export class RendererManager {
private renderTree: RootNode | null = null;
private listeners = new Set<() => void>();
constructor(private editor: EditorCore) {}
constructor(private editor: EditorCore) { }
setRenderTree({ renderTree }: { renderTree: RootNode | null }): void {
this.renderTree = renderTree;

View File

@ -6,7 +6,7 @@ import {
ensureMainScene,
canDeleteScene,
findCurrentScene,
} from "@/lib/scene-utils";
} from "@/lib/scenes";
import {
getFrameTime,
isBookmarkAtTime,

View File

@ -9,9 +9,9 @@ import {
import { useEditor } from "@/hooks/use-editor";
import { useElementSelection } from "@/hooks/timeline/element/use-element-selection";
import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
import { snapTimeToFrame } from "@/lib/time-utils";
import { snapTimeToFrame } from "@/lib/time";
import { computeDropTarget } from "@/lib/timeline/drop-utils";
import { generateUUID } from "@/lib/utils";
import { generateUUID } from "@/utils/id";
import { useTimelineSnapping } from "@/hooks/timeline/use-timeline-snapping";
import type {
DropTarget,

View File

@ -1,6 +1,6 @@
import { useState, useEffect, useRef } from "react";
import { TimelineElement, TimelineTrack } from "@/types/timeline";
import { snapTimeToFrame } from "@/lib/time-utils";
import { snapTimeToFrame } from "@/lib/time";
import { EditorCore } from "@/core";
import {
useTimelineSnapping,

View File

@ -3,7 +3,7 @@ import { useEditor } from "@/hooks/use-editor";
import { processMediaAssets } from "@/lib/media/processing";
import { toast } from "sonner";
import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
import { snapTimeToFrame } from "@/lib/time-utils";
import { snapTimeToFrame } from "@/lib/time";
import {
buildTextElement,
buildStickerElement,

View File

@ -1,7 +1,7 @@
import { useCallback, useRef } from "react";
import type { MutableRefObject, RefObject } from "react";
import { TIMELINE_CONSTANTS } from "@/constants/timeline-constants";
import { getSnappedSeekTime } from "@/lib/time-utils";
import { getSnappedSeekTime } from "@/lib/time";
import { useEditor } from "../use-editor";
interface UseTimelineInteractionsProps {

View File

@ -1,4 +1,4 @@
import { getSnappedSeekTime } from "@/lib/time-utils";
import { getSnappedSeekTime } from "@/lib/time";
import { useState, useEffect, useCallback, useRef } from "react";
import { useEdgeAutoScroll } from "@/hooks/timeline/use-edge-auto-scroll";
import { useEditor } from "../use-editor";

View File

@ -6,7 +6,7 @@ import { ACTIONS, type TAction } from "@/lib/actions";
import {
getPlatformAlternateKey,
getPlatformSpecialKey,
} from "@/lib/keyboard-utils";
} from "@/utils/platform";
export interface KeyboardShortcut {
id: string;

View File

@ -1,7 +1,7 @@
import { Command } from "@/lib/commands/base-command";
import { EditorCore } from "@/core";
import type { MediaAsset } from "@/types/assets";
import { generateUUID } from "@/lib/utils";
import { generateUUID } from "@/utils/id";
import { storageService } from "@/services/storage/storage-service";
export class AddMediaAssetCommand extends Command {

View File

@ -1,7 +1,7 @@
import { Command } from "@/lib/commands/base-command";
import { EditorCore } from "@/core";
import type { TScene } from "@/types/timeline";
import { buildDefaultScene } from "@/lib/scene-utils";
import { buildDefaultScene } from "@/lib/scenes";
export class CreateSceneCommand extends Command {
private savedScenes: TScene[] | null = null;

View File

@ -1,7 +1,7 @@
import { Command } from "@/lib/commands/base-command";
import { EditorCore } from "@/core";
import type { TScene } from "@/types/timeline";
import { canDeleteScene, getFallbackSceneAfterDelete } from "@/lib/scene-utils";
import { canDeleteScene, getFallbackSceneAfterDelete } from "@/lib/scenes";
export class DeleteSceneCommand extends Command {
private savedScenes: TScene[] | null = null;

View File

@ -1,7 +1,7 @@
import { Command } from "@/lib/commands/base-command";
import { EditorCore } from "@/core";
import type { TScene } from "@/types/timeline";
import { updateSceneInArray } from "@/lib/scene-utils";
import { updateSceneInArray } from "@/lib/scenes";
import {
getFrameTime,
removeBookmarkFromArray,

View File

@ -1,7 +1,7 @@
import { Command } from "@/lib/commands/base-command";
import { EditorCore } from "@/core";
import type { TScene } from "@/types/timeline";
import { updateSceneInArray } from "@/lib/scene-utils";
import { updateSceneInArray } from "@/lib/scenes";
export class RenameSceneCommand extends Command {
private savedScenes: TScene[] | null = null;

View File

@ -1,7 +1,7 @@
import { Command } from "@/lib/commands/base-command";
import { EditorCore } from "@/core";
import type { TScene } from "@/types/timeline";
import { updateSceneInArray } from "@/lib/scene-utils";
import { updateSceneInArray } from "@/lib/scenes";
import {
getFrameTime,
toggleBookmarkInArray,

View File

@ -5,7 +5,7 @@ import type {
TimelineElement,
ClipboardItem,
} from "@/types/timeline";
import { generateUUID } from "@/lib/utils";
import { generateUUID } from "@/utils/id";
import { wouldElementOverlap } from "@/lib/timeline/element-utils";
import {
buildEmptyTrack,

View File

@ -1,6 +1,6 @@
import { Command } from "@/lib/commands/base-command";
import type { TimelineElement, TimelineTrack } from "@/types/timeline";
import { generateUUID } from "@/lib/utils";
import { generateUUID } from "@/utils/id";
import { EditorCore } from "@/core";
import {
buildEmptyTrack,

View File

@ -7,7 +7,7 @@ import type {
TrackType,
ElementType,
} from "@/types/timeline";
import { generateUUID } from "@/lib/utils";
import { generateUUID } from "@/utils/id";
import {
requiresMediaId,
wouldElementOverlap,

View File

@ -1,6 +1,6 @@
import { Command } from "@/lib/commands/base-command";
import type { TimelineTrack } from "@/types/timeline";
import { generateUUID } from "@/lib/utils";
import { generateUUID } from "@/utils/id";
import { EditorCore } from "@/core";
export class SplitElementsCommand extends Command {

View File

@ -1,6 +1,6 @@
import { Command } from "@/lib/commands/base-command";
import type { TrackType, TimelineTrack } from "@/types/timeline";
import { generateUUID } from "@/lib/utils";
import { generateUUID } from "@/utils/id";
import { EditorCore } from "@/core";
import {
buildEmptyTrack,

View File

@ -1,11 +0,0 @@
export function dimensionToAspectRatio({
width,
height,
}: {
width: number;
height: number;
}): string {
const gcd = (a: number, b: number): number => (b === 0 ? a : gcd(b, a % b));
const divisor = gcd(width, height);
return `${width / divisor}:${height / divisor}`;
}

Some files were not shown because too many files have changed in this diff Show More