mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-27 16:25:35 +00:00
feat(blur): implement video blur annotation support
This commit is contained in:
@@ -111,6 +111,17 @@ export function AnnotationOverlay({
|
||||
</div>
|
||||
);
|
||||
|
||||
case "blur":
|
||||
return (
|
||||
<div
|
||||
className="h-full w-full bg-slate-400/10"
|
||||
style={{
|
||||
backdropFilter: "blur(12px)",
|
||||
WebkitBackdropFilter: "blur(12px)",
|
||||
boxShadow: isSelected ? "inset 0 0 0 1px rgba(255,255,255,0.2)" : "none",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useRef, useState, useEffect, useMemo } from "react";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Trash2, Type, Image as ImageIcon, Upload, Bold, Italic, Underline, AlignLeft, AlignCenter, AlignRight, ChevronDown, Info } from "lucide-react";
|
||||
import { Trash2, Type, Image as ImageIcon, Upload, Bold, Italic, Underline, AlignLeft, AlignCenter, AlignRight, ChevronDown, Info, SquareDashed } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import Block from '@uiw/react-color-block';
|
||||
import type { AnnotationRegion, AnnotationType, ArrowDirection, FigureData } from "./types";
|
||||
@@ -128,7 +128,7 @@ export function AnnotationSettingsPanel({
|
||||
|
||||
{/* Type Selector */}
|
||||
<Tabs value={annotation.type} onValueChange={(value) => onTypeChange(value as AnnotationType)} className="mb-6">
|
||||
<TabsList className="mb-4 bg-white/5 border border-white/5 p-1 w-full grid grid-cols-3 h-auto rounded-xl">
|
||||
<TabsList className="mb-4 bg-white/5 border border-white/5 p-1 w-full grid grid-cols-4 h-auto rounded-xl">
|
||||
<TabsTrigger value="text" className="data-[state=active]:bg-[#2563EB] data-[state=active]:text-white text-slate-400 py-2 rounded-lg transition-all gap-2">
|
||||
<Type className="w-4 h-4" />
|
||||
{t('annotations.text')}
|
||||
@@ -143,6 +143,10 @@ export function AnnotationSettingsPanel({
|
||||
</svg>
|
||||
{t('annotations.arrow')}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="blur" className="data-[state=active]:bg-[#2563EB] data-[state=active]:text-white text-slate-400 py-2 rounded-lg transition-all gap-2">
|
||||
<SquareDashed className="w-4 h-4" />
|
||||
{t('annotations.blur')}
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
{/* Text Content */}
|
||||
@@ -499,6 +503,18 @@ export function AnnotationSettingsPanel({
|
||||
</Popover>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="blur" className="mt-0 space-y-4">
|
||||
<div className="p-4 bg-white/5 rounded-xl border border-white/10 flex flex-col items-center justify-center text-center">
|
||||
<div className="w-12 h-12 rounded-full bg-[#2563EB]/20 flex items-center justify-center mb-3">
|
||||
<SquareDashed className="w-6 h-6 text-[#2563EB]" />
|
||||
</div>
|
||||
<h4 className="text-sm font-medium text-slate-200 mb-1">{t('annotations.blur')}</h4>
|
||||
<p className="text-xs text-slate-400 max-w-[200px]">
|
||||
Resize and reposition the box on the video to blur sensitive information.
|
||||
</p>
|
||||
</div>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
<Button
|
||||
|
||||
@@ -399,7 +399,7 @@ export function normalizeProjectEditor(editor: Partial<ProjectEditorState>): Pro
|
||||
id: region.id,
|
||||
startMs,
|
||||
endMs,
|
||||
type: region.type === "image" || region.type === "figure" ? region.type : "text",
|
||||
type: region.type === "image" || region.type === "figure" || region.type === "blur" ? region.type : "text",
|
||||
content: typeof region.content === "string" ? region.content : "",
|
||||
textContent: typeof region.textContent === "string" ? region.textContent : undefined,
|
||||
imageContent: typeof region.imageContent === "string" ? region.imageContent : undefined,
|
||||
|
||||
@@ -175,7 +175,7 @@ export function trimsToClips(trims: TrimRegion[], totalDurationMs: number): Clip
|
||||
return clips;
|
||||
}
|
||||
|
||||
export type AnnotationType = "text" | "image" | "figure";
|
||||
export type AnnotationType = "text" | "image" | "figure" | "blur";
|
||||
|
||||
export type ArrowDirection =
|
||||
| "up"
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"text": "Text",
|
||||
"image": "Image",
|
||||
"arrow": "Arrow",
|
||||
"blur": "Blur",
|
||||
"textContent": "Text Content",
|
||||
"textPlaceholder": "Enter your text...",
|
||||
"fontStyle": "Font Style",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"text": "Texto",
|
||||
"image": "Imagen",
|
||||
"arrow": "Flecha",
|
||||
"blur": "Desenfoque",
|
||||
"textContent": "Contenido de texto",
|
||||
"textPlaceholder": "Ingresa tu texto...",
|
||||
"fontStyle": "Estilo de fuente",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"text": "文本",
|
||||
"image": "图片",
|
||||
"arrow": "箭头",
|
||||
"blur": "模糊",
|
||||
"textContent": "文本内容",
|
||||
"textPlaceholder": "输入文本...",
|
||||
"fontStyle": "字体样式",
|
||||
|
||||
@@ -358,6 +358,16 @@ export async function renderAnnotations(
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case "blur":
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.rect(x, y, width, height);
|
||||
ctx.clip();
|
||||
ctx.filter = `blur(${20 * scaleFactor}px)`;
|
||||
ctx.drawImage(ctx.canvas, 0, 0);
|
||||
ctx.restore();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user