added free trial timer at welcome screen
This commit is contained in:
@ -33,6 +33,8 @@ import {
|
|||||||
MapPin,
|
MapPin,
|
||||||
Music,
|
Music,
|
||||||
ListVideo,
|
ListVideo,
|
||||||
|
Clock,
|
||||||
|
AlertTriangle,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
|
||||||
const LAST_MEDIA_PATH_KEY = 'talkedit:lastMediaPath';
|
const LAST_MEDIA_PATH_KEY = 'talkedit:lastMediaPath';
|
||||||
@ -136,6 +138,8 @@ export default function App() {
|
|||||||
const [lastSavedSignature, setLastSavedSignature] = useState<string | null>(null);
|
const [lastSavedSignature, setLastSavedSignature] = useState<string | null>(null);
|
||||||
const [showFileMenu, setShowFileMenu] = useState(false);
|
const [showFileMenu, setShowFileMenu] = useState(false);
|
||||||
const canEdit = useLicenseStore((s) => s.canEdit);
|
const canEdit = useLicenseStore((s) => s.canEdit);
|
||||||
|
const licenseStatus = useLicenseStore((s) => s.status);
|
||||||
|
const setShowLicenseDialog = useLicenseStore((s) => s.setShowDialog);
|
||||||
|
|
||||||
const projectSignature = useMemo(() => {
|
const projectSignature = useMemo(() => {
|
||||||
if (!videoPath) return null;
|
if (!videoPath) return null;
|
||||||
@ -505,64 +509,94 @@ export default function App() {
|
|||||||
|
|
||||||
if (!videoPath) {
|
if (!videoPath) {
|
||||||
return (
|
return (
|
||||||
<div className="h-screen flex flex-col items-center justify-center gap-8 bg-editor-bg px-6">
|
<div className="h-screen flex flex-col bg-editor-bg">
|
||||||
<div className="flex flex-col items-center gap-3">
|
<div className="flex-1 flex flex-col items-center justify-center gap-8 px-6">
|
||||||
<Film className="w-14 h-14 text-editor-accent opacity-80" />
|
<div className="flex flex-col items-center gap-3">
|
||||||
<h1 className="text-3xl font-semibold tracking-tight">TalkEdit</h1>
|
<Film className="w-14 h-14 text-editor-accent opacity-80" />
|
||||||
<p className="text-editor-text-muted text-sm max-w-sm text-center">
|
<h1 className="text-3xl font-semibold tracking-tight">TalkEdit</h1>
|
||||||
Offline AI-powered video editor.
|
<p className="text-editor-text-muted text-sm max-w-sm text-center">
|
||||||
|
Offline AI-powered video editor.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Whisper model selector */}
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<label className="text-xs text-editor-text-muted whitespace-nowrap">Model:</label>
|
||||||
|
<select
|
||||||
|
value={whisperModel}
|
||||||
|
onChange={(e) => setWhisperModel(e.target.value)}
|
||||||
|
className="px-3 py-1.5 bg-editor-surface border border-editor-border rounded-lg text-xs text-black focus:outline-none focus:border-editor-accent"
|
||||||
|
>
|
||||||
|
<optgroup label="Multilingual (any language)">
|
||||||
|
<option value="tiny">tiny — ~75 MB · fastest, low accuracy</option>
|
||||||
|
<option value="base">base — ~140 MB · fast, decent accuracy</option>
|
||||||
|
<option value="small">small — ~460 MB · good balance</option>
|
||||||
|
<option value="medium">medium — ~1.5 GB · better accuracy</option>
|
||||||
|
<option value="large-v2">large-v2 — ~2.9 GB · high accuracy</option>
|
||||||
|
<option value="large-v3">large-v3 — ~2.9 GB · best overall ★</option>
|
||||||
|
<option value="large-v3-turbo">large-v3-turbo — ~1.6 GB · fast + accurate ★</option>
|
||||||
|
<option value="distil-large-v3">distil-large-v3 — ~1.5 GB · fast, near large-v3 quality</option>
|
||||||
|
</optgroup>
|
||||||
|
<optgroup label="English-only (faster & more accurate for English)">
|
||||||
|
<option value="tiny.en">tiny.en — ~75 MB · fastest English</option>
|
||||||
|
<option value="base.en">base.en — ~140 MB · fast English</option>
|
||||||
|
<option value="small.en">small.en — ~460 MB · good English</option>
|
||||||
|
<option value="medium.en">medium.en — ~1.5 GB · great English</option>
|
||||||
|
<option value="distil-small.en">distil-small.en — ~190 MB · fast English ★</option>
|
||||||
|
<option value="distil-medium.en">distil-medium.en — ~750 MB · best fast English ★</option>
|
||||||
|
</optgroup>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<p className="text-[11px] text-editor-text-muted text-center max-w-sm">
|
||||||
|
For noisy/YouTube videos use <span className="text-white">large-v3</span> or <span className="text-white">large-v3-turbo</span>.
|
||||||
|
English-only models are ~10% faster and more accurate for English content.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div className="flex flex-col items-center gap-3">
|
||||||
|
<button
|
||||||
|
onClick={handleOpenFile}
|
||||||
|
className="flex items-center gap-2 px-6 py-3 bg-editor-accent hover:bg-editor-accent-hover rounded-lg text-white font-medium transition-colors"
|
||||||
|
>
|
||||||
|
<FolderOpen className="w-5 h-5" />
|
||||||
|
Open Video File
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleLoadProject}
|
||||||
|
className="flex items-center gap-2 px-4 py-2 text-sm text-editor-text-muted hover:text-editor-text hover:bg-editor-surface rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
<FileInput className="w-4 h-4" />
|
||||||
|
Load Project (.aive)
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Whisper model selector */}
|
{licenseStatus?.tag === 'Trial' && (
|
||||||
<div className="flex items-center gap-3">
|
<div className="h-9 flex items-center justify-center gap-2 px-4 bg-editor-accent/10 border-t border-editor-accent/20 shrink-0">
|
||||||
<label className="text-xs text-editor-text-muted whitespace-nowrap">Model:</label>
|
<Clock className="w-3.5 h-3.5 text-editor-accent shrink-0" />
|
||||||
<select
|
<span className="text-xs text-editor-accent">
|
||||||
value={whisperModel}
|
Free trial: {licenseStatus.days_remaining} day{licenseStatus.days_remaining !== 1 ? 's' : ''} remaining
|
||||||
onChange={(e) => setWhisperModel(e.target.value)}
|
</span>
|
||||||
className="px-3 py-1.5 bg-editor-surface border border-editor-border rounded-lg text-xs text-black focus:outline-none focus:border-editor-accent"
|
<button
|
||||||
>
|
onClick={() => setShowLicenseDialog(true)}
|
||||||
<optgroup label="Multilingual (any language)">
|
className="text-xs text-editor-accent underline font-medium hover:text-editor-accent-hover ml-2"
|
||||||
<option value="tiny">tiny — ~75 MB · fastest, low accuracy</option>
|
>
|
||||||
<option value="base">base — ~140 MB · fast, decent accuracy</option>
|
Activate license
|
||||||
<option value="small">small — ~460 MB · good balance</option>
|
</button>
|
||||||
<option value="medium">medium — ~1.5 GB · better accuracy</option>
|
</div>
|
||||||
<option value="large-v2">large-v2 — ~2.9 GB · high accuracy</option>
|
)}
|
||||||
<option value="large-v3">large-v3 — ~2.9 GB · best overall ★</option>
|
|
||||||
<option value="large-v3-turbo">large-v3-turbo — ~1.6 GB · fast + accurate ★</option>
|
|
||||||
<option value="distil-large-v3">distil-large-v3 — ~1.5 GB · fast, near large-v3 quality</option>
|
|
||||||
</optgroup>
|
|
||||||
<optgroup label="English-only (faster & more accurate for English)">
|
|
||||||
<option value="tiny.en">tiny.en — ~75 MB · fastest English</option>
|
|
||||||
<option value="base.en">base.en — ~140 MB · fast English</option>
|
|
||||||
<option value="small.en">small.en — ~460 MB · good English</option>
|
|
||||||
<option value="medium.en">medium.en — ~1.5 GB · great English</option>
|
|
||||||
<option value="distil-small.en">distil-small.en — ~190 MB · fast English ★</option>
|
|
||||||
<option value="distil-medium.en">distil-medium.en — ~750 MB · best fast English ★</option>
|
|
||||||
</optgroup>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<p className="text-[11px] text-editor-text-muted text-center max-w-sm">
|
|
||||||
For noisy/YouTube videos use <span className="text-white">large-v3</span> or <span className="text-white">large-v3-turbo</span>.
|
|
||||||
English-only models are ~10% faster and more accurate for English content.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="flex flex-col items-center gap-3">
|
{licenseStatus?.tag === 'Expired' && (
|
||||||
<button
|
<div className="h-9 flex items-center justify-center gap-2 px-4 bg-red-500/15 border-t border-red-500/30 shrink-0">
|
||||||
onClick={handleOpenFile}
|
<AlertTriangle className="w-3.5 h-3.5 text-red-400 shrink-0" />
|
||||||
className="flex items-center gap-2 px-6 py-3 bg-editor-accent hover:bg-editor-accent-hover rounded-lg text-white font-medium transition-colors"
|
<span className="text-xs text-red-300">Trial expired</span>
|
||||||
>
|
<button
|
||||||
<FolderOpen className="w-5 h-5" />
|
onClick={() => setShowLicenseDialog(true)}
|
||||||
Open Video File
|
className="text-xs text-red-300 underline font-medium hover:text-red-200 ml-2"
|
||||||
</button>
|
>
|
||||||
<button
|
Activate license
|
||||||
onClick={handleLoadProject}
|
</button>
|
||||||
className="flex items-center gap-2 px-4 py-2 text-sm text-editor-text-muted hover:text-editor-text hover:bg-editor-surface rounded-lg transition-colors"
|
</div>
|
||||||
>
|
)}
|
||||||
<FileInput className="w-4 h-4" />
|
|
||||||
Load Project (.aive)
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user