phase 1: motion language
This commit is contained in:
parent
7bd798b9d1
commit
11e138ae36
41 changed files with 181 additions and 184 deletions
|
|
@ -173,7 +173,7 @@ export default function EPUBPage() {
|
||||||
<p className="text-red-500 mb-4">{error}</p>
|
<p className="text-red-500 mb-4">{error}</p>
|
||||||
<Link
|
<Link
|
||||||
href="/app"
|
href="/app"
|
||||||
className="inline-flex items-center px-3 py-1 bg-base text-foreground rounded-lg hover:bg-offbase transition-all duration-200 ease-in-out hover:scale-[1.04] hover:text-accent"
|
className="inline-flex items-center px-3 py-1 bg-base text-foreground rounded-lg hover:bg-offbase transition duration-base ease-standard hover:text-accent"
|
||||||
>
|
>
|
||||||
<svg className="w-4 h-4 mr-2 text-muted" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4 mr-2 text-muted" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||||
|
|
@ -190,7 +190,7 @@ export default function EPUBPage() {
|
||||||
left={
|
left={
|
||||||
<Link
|
<Link
|
||||||
href="/app"
|
href="/app"
|
||||||
className="inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition-all duration-200 ease-in-out hover:scale-[1.04] hover:text-accent"
|
className="inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition duration-base ease-standard hover:text-accent"
|
||||||
aria-label="Back to documents"
|
aria-label="Back to documents"
|
||||||
>
|
>
|
||||||
<svg className="w-3 h-3 mr-2" fill="currentColor" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-3 h-3 mr-2" fill="currentColor" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ export default function HTMLPage() {
|
||||||
<p className="text-red-500 mb-4">{error}</p>
|
<p className="text-red-500 mb-4">{error}</p>
|
||||||
<Link
|
<Link
|
||||||
href="/app"
|
href="/app"
|
||||||
className="inline-flex items-center px-3 py-1 bg-base text-foreground rounded-lg hover:bg-offbase transition-all duration-200 ease-in-out hover:scale-[1.04] hover:text-accent"
|
className="inline-flex items-center px-3 py-1 bg-base text-foreground rounded-lg hover:bg-offbase transition duration-base ease-standard hover:text-accent"
|
||||||
>
|
>
|
||||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||||
|
|
@ -177,7 +177,7 @@ export default function HTMLPage() {
|
||||||
left={
|
left={
|
||||||
<Link
|
<Link
|
||||||
href="/app"
|
href="/app"
|
||||||
className="inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition-all duration-200 ease-in-out hover:scale-[1.04] hover:text-accent"
|
className="inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition duration-base ease-standard hover:text-accent"
|
||||||
aria-label="Back to documents"
|
aria-label="Back to documents"
|
||||||
>
|
>
|
||||||
<svg className="w-3 h-3 mr-2" fill="currentColor" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-3 h-3 mr-2" fill="currentColor" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,7 @@ export default function PDFViewerPage() {
|
||||||
<Link
|
<Link
|
||||||
href="/app"
|
href="/app"
|
||||||
onClick={handleBackToDocuments}
|
onClick={handleBackToDocuments}
|
||||||
className="inline-flex items-center px-3 py-1 bg-base text-foreground rounded-lg hover:bg-offbase transition-all duration-200 ease-in-out hover:scale-[1.04] hover:text-accent"
|
className="inline-flex items-center px-3 py-1 bg-base text-foreground rounded-lg hover:bg-offbase transition duration-base ease-standard hover:text-accent"
|
||||||
>
|
>
|
||||||
<svg className="w-4 h-4 mr-2 text-muted" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4 mr-2 text-muted" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||||
|
|
@ -309,7 +309,7 @@ export default function PDFViewerPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full w-full bg-base">
|
<div className="h-full w-full bg-base">
|
||||||
<div className={`mx-auto flex h-full items-center px-4 py-6 transition-all duration-300 ease-out ${showDetailedParseLoader ? 'max-w-lg' : 'max-w-md'}`}>
|
<div className={`mx-auto flex h-full items-center px-4 py-6 transition duration-slow ease-standard ${showDetailedParseLoader ? 'max-w-lg' : 'max-w-md'}`}>
|
||||||
{showDetailedParseLoader ? (
|
{showDetailedParseLoader ? (
|
||||||
<div className="w-full rounded-xl border border-offbase bg-offbase/95 shadow-sm overflow-hidden">
|
<div className="w-full rounded-xl border border-offbase bg-offbase/95 shadow-sm overflow-hidden">
|
||||||
<div className="h-1 bg-[linear-gradient(90deg,var(--accent),transparent_80%)]" />
|
<div className="h-1 bg-[linear-gradient(90deg,var(--accent),transparent_80%)]" />
|
||||||
|
|
@ -331,7 +331,7 @@ export default function PDFViewerPage() {
|
||||||
</div>
|
</div>
|
||||||
<div className="h-2 w-full rounded-full bg-offbase overflow-hidden">
|
<div className="h-2 w-full rounded-full bg-offbase overflow-hidden">
|
||||||
<div
|
<div
|
||||||
className="h-full bg-accent transition-all duration-300 ease-out"
|
className="h-full bg-accent transition duration-slow ease-standard"
|
||||||
style={{ width: `${hasMeasuredProgress ? progressPercent : 6}%` }}
|
style={{ width: `${hasMeasuredProgress ? progressPercent : 6}%` }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -354,7 +354,7 @@ export default function PDFViewerPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="w-full rounded-xl border border-offbase bg-offbase/95 p-4 shadow-sm transition-all duration-300 ease-out overflow-hidden">
|
<div className="w-full rounded-xl border border-offbase bg-offbase/95 p-4 shadow-sm transition duration-slow ease-standard overflow-hidden">
|
||||||
<div className="h-0.5 -mx-4 -mt-4 mb-3 bg-[linear-gradient(90deg,var(--accent),transparent_75%)]" />
|
<div className="h-0.5 -mx-4 -mt-4 mb-3 bg-[linear-gradient(90deg,var(--accent),transparent_75%)]" />
|
||||||
<div className="flex items-start justify-between gap-3">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
|
|
@ -384,7 +384,7 @@ export default function PDFViewerPage() {
|
||||||
<Link
|
<Link
|
||||||
href="/app"
|
href="/app"
|
||||||
onClick={handleBackToDocuments}
|
onClick={handleBackToDocuments}
|
||||||
className="inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition-all duration-200 ease-in-out hover:scale-[1.04] hover:text-accent"
|
className="inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition duration-base ease-standard hover:text-accent"
|
||||||
aria-label="Back to documents"
|
aria-label="Back to documents"
|
||||||
>
|
>
|
||||||
<svg className="w-3 h-3 mr-2" fill="currentColor" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-3 h-3 mr-2" fill="currentColor" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ function SignInContent() {
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isAnyLoading}
|
disabled={isAnyLoading}
|
||||||
onClick={handleSignIn}
|
onClick={handleSignIn}
|
||||||
className={buttonClass({ variant: 'primary', size: 'md', className: 'w-full hover:scale-[1.02]' })}
|
className={buttonClass({ variant: 'primary', size: 'md', className: 'w-full' })}
|
||||||
>
|
>
|
||||||
{loadingEmail ? <LoadingSpinner className="w-4 h-4 mx-auto" /> : 'Connect'}
|
{loadingEmail ? <LoadingSpinner className="w-4 h-4 mx-auto" /> : 'Connect'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -202,7 +202,7 @@ function SignInContent() {
|
||||||
className={buttonClass({
|
className={buttonClass({
|
||||||
variant: 'outline',
|
variant: 'outline',
|
||||||
size: 'md',
|
size: 'md',
|
||||||
className: 'w-full hover:scale-[1.02] flex items-center justify-center gap-2',
|
className: 'w-full flex items-center justify-center gap-2',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{loadingGithub ? (
|
{loadingGithub ? (
|
||||||
|
|
@ -222,7 +222,7 @@ function SignInContent() {
|
||||||
type="button"
|
type="button"
|
||||||
disabled={isAnyLoading}
|
disabled={isAnyLoading}
|
||||||
onClick={handleAnonymousContinue}
|
onClick={handleAnonymousContinue}
|
||||||
className={buttonClass({ variant: 'outline', size: 'md', className: 'w-full hover:scale-[1.02]' })}
|
className={buttonClass({ variant: 'outline', size: 'md', className: 'w-full' })}
|
||||||
>
|
>
|
||||||
{loadingAnonymous ? <LoadingSpinner className="w-4 h-4 mx-auto" /> : 'Continue anonymously'}
|
{loadingAnonymous ? <LoadingSpinner className="w-4 h-4 mx-auto" /> : 'Continue anonymously'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -234,7 +234,7 @@ export default function SignUpPage() {
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
onClick={handleSignUp}
|
onClick={handleSignUp}
|
||||||
className={buttonClass({ variant: 'primary', size: 'md', className: 'w-full hover:scale-[1.02]' })}
|
className={buttonClass({ variant: 'primary', size: 'md', className: 'w-full' })}
|
||||||
>
|
>
|
||||||
{loading ? <LoadingSpinner className="w-4 h-4 mx-auto" /> : 'Create Account'}
|
{loading ? <LoadingSpinner className="w-4 h-4 mx-auto" /> : 'Create Account'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -560,7 +560,7 @@ export function AudiobookExportModal({
|
||||||
disabled={chapters.length > 0 || settingsLocked}
|
disabled={chapters.length > 0 || settingsLocked}
|
||||||
>
|
>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<ListboxButton className="relative cursor-pointer rounded-lg bg-base py-1.5 pl-3 pr-10 text-left text-foreground focus:outline-none focus:ring-2 focus:ring-accent transform transition-transform duration-200 ease-in-out hover:scale-[1.01] hover:text-accent w-full">
|
<ListboxButton className="relative cursor-pointer rounded-lg bg-base py-1.5 pl-3 pr-10 text-left text-foreground focus:outline-none focus:ring-2 focus:ring-accent transform transition-transform duration-base ease-standard hover:text-accent w-full">
|
||||||
<span className="block truncate text-sm font-medium">{format.toUpperCase()}</span>
|
<span className="block truncate text-sm font-medium">{format.toUpperCase()}</span>
|
||||||
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||||
<ChevronUpDownIcon className="h-4 w-4 text-muted" />
|
<ChevronUpDownIcon className="h-4 w-4 text-muted" />
|
||||||
|
|
@ -568,7 +568,7 @@ export function AudiobookExportModal({
|
||||||
</ListboxButton>
|
</ListboxButton>
|
||||||
<Transition
|
<Transition
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
leave="transition ease-in duration-100"
|
leave="transition ease-standard duration-fast"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -673,7 +673,7 @@ export function AudiobookExportModal({
|
||||||
className="flex-1 inline-flex justify-center rounded-lg bg-accent px-3 py-2 text-sm
|
className="flex-1 inline-flex justify-center rounded-lg bg-accent px-3 py-2 text-sm
|
||||||
font-medium text-background hover:bg-secondary-accent focus:outline-none
|
font-medium text-background hover:bg-secondary-accent focus:outline-none
|
||||||
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
||||||
transform transition-transform duration-200 ease-in-out hover:scale-[1.01] disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100"
|
transform transition-transform duration-base ease-standard disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
Start Generation
|
Start Generation
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -685,7 +685,7 @@ export function AudiobookExportModal({
|
||||||
className="flex-1 inline-flex justify-center rounded-lg bg-accent px-3 py-2 text-sm
|
className="flex-1 inline-flex justify-center rounded-lg bg-accent px-3 py-2 text-sm
|
||||||
font-medium text-background hover:bg-secondary-accent focus:outline-none
|
font-medium text-background hover:bg-secondary-accent focus:outline-none
|
||||||
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
||||||
transform transition-transform duration-200 ease-in-out hover:scale-[1.01] disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100"
|
transform transition-transform duration-base ease-standard disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
Resume
|
Resume
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -697,7 +697,7 @@ export function AudiobookExportModal({
|
||||||
className="inline-flex justify-center rounded-lg border border-red-500 bg-transparent px-3 py-2 text-sm
|
className="inline-flex justify-center rounded-lg border border-red-500 bg-transparent px-3 py-2 text-sm
|
||||||
font-medium text-red-500 hover:bg-red-500 hover:text-background focus:outline-none
|
font-medium text-red-500 hover:bg-red-500 hover:text-background focus:outline-none
|
||||||
focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-2
|
focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-2
|
||||||
transform transition-transform duration-200 ease-in-out hover:scale-[1.01]"
|
transform transition-transform duration-base ease-standard"
|
||||||
title="Delete all generated chapters/pages for this document"
|
title="Delete all generated chapters/pages for this document"
|
||||||
>
|
>
|
||||||
Reset
|
Reset
|
||||||
|
|
@ -760,7 +760,7 @@ export function AudiobookExportModal({
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleRegenerateChapter(chapter)}
|
onClick={() => handleRegenerateChapter(chapter)}
|
||||||
disabled={regeneratingChapter !== null || chapter.status === 'generating' || isGenerating}
|
disabled={regeneratingChapter !== null || chapter.status === 'generating' || isGenerating}
|
||||||
className="inline-flex items-center justify-center rounded-full bg-offbase text-accent hover:bg-accent/20 p-1.5 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent transform transition-transform duration-200 ease-in-out hover:scale-[1.04] disabled:opacity-50 disabled:cursor-not-allowed"
|
className="inline-flex items-center justify-center rounded-full bg-offbase text-accent hover:bg-accent/20 p-1.5 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent transform transition-transform duration-base ease-standard disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
title={chapter.status === 'generating' ? 'Generating...' : 'Regenerate this chapter'}
|
title={chapter.status === 'generating' ? 'Generating...' : 'Regenerate this chapter'}
|
||||||
>
|
>
|
||||||
<RefreshIcon className={`h-4 w-4 ${regeneratingChapter === chapter.index || chapter.status === 'generating' ? 'animate-spin' : ''}`} />
|
<RefreshIcon className={`h-4 w-4 ${regeneratingChapter === chapter.index || chapter.status === 'generating' ? 'animate-spin' : ''}`} />
|
||||||
|
|
@ -782,17 +782,17 @@ export function AudiobookExportModal({
|
||||||
{((onRegenerateChapter && !isGenerating) || chapter.status === 'completed') && (
|
{((onRegenerateChapter && !isGenerating) || chapter.status === 'completed') && (
|
||||||
<Menu as="div" className="relative inline-block text-left">
|
<Menu as="div" className="relative inline-block text-left">
|
||||||
<MenuButton
|
<MenuButton
|
||||||
className="inline-flex items-center justify-center rounded-md p-1.5 hover:bg-background focus:outline-none focus-visible:ring-2 focus-visible:ring-accent text-muted hover:text-foreground transform transition-transform duration-200 ease-in-out hover:scale-[1.04]"
|
className="inline-flex items-center justify-center rounded-md p-1.5 hover:bg-background focus:outline-none focus-visible:ring-2 focus-visible:ring-accent text-muted hover:text-foreground transform transition-transform duration-base ease-standard"
|
||||||
title="Chapter actions"
|
title="Chapter actions"
|
||||||
>
|
>
|
||||||
<DotsVerticalIcon className="h-5 w-5" />
|
<DotsVerticalIcon className="h-5 w-5" />
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
<Transition
|
<Transition
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="transition ease-out duration-100"
|
enter="transition ease-standard duration-fast"
|
||||||
enterFrom="transform opacity-0 scale-95"
|
enterFrom="transform opacity-0 scale-95"
|
||||||
enterTo="transform opacity-100 scale-100"
|
enterTo="transform opacity-100 scale-100"
|
||||||
leave="transition ease-in duration-75"
|
leave="transition ease-standard duration-fast"
|
||||||
leaveFrom="transform opacity-100 scale-100"
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
leaveTo="transform opacity-0 scale-95"
|
leaveTo="transform opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
|
|
@ -873,10 +873,10 @@ export function AudiobookExportModal({
|
||||||
onClick={handleDownloadComplete}
|
onClick={handleDownloadComplete}
|
||||||
disabled={isCombining}
|
disabled={isCombining}
|
||||||
className="w-full inline-flex justify-center items-center space-x-2 rounded-lg bg-accent px-3 py-1.5 text-sm
|
className="w-full inline-flex justify-center items-center space-x-2 rounded-lg bg-accent px-3 py-1.5 text-sm
|
||||||
disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100
|
disabled:opacity-50 disabled:cursor-not-allowed
|
||||||
font-medium text-background hover:bg-secondary-accent focus:outline-none
|
font-medium text-background hover:bg-secondary-accent focus:outline-none
|
||||||
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
||||||
transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-background"
|
transform transition-transform duration-base ease-standard hover:text-background"
|
||||||
>
|
>
|
||||||
<DownloadIcon className="h-5 w-5" />
|
<DownloadIcon className="h-5 w-5" />
|
||||||
<span>{isCombining ? 'Combining chapters...' : `Full Download (${format.toUpperCase()})`}</span>
|
<span>{isCombining ? 'Combining chapters...' : `Full Download (${format.toUpperCase()})`}</span>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export function CodeBlock({ children }: { children: string }) {
|
||||||
className={buttonClass({
|
className={buttonClass({
|
||||||
variant: 'secondary',
|
variant: 'secondary',
|
||||||
size: 'icon',
|
size: 'icon',
|
||||||
className: 'absolute top-2 right-2 h-7 w-7 opacity-0 group-hover:opacity-100 focus:opacity-100 hover:scale-[1.05]',
|
className: 'absolute top-2 right-2 h-7 w-7 opacity-0 group-hover:opacity-100 focus:opacity-100',
|
||||||
})}
|
})}
|
||||||
title="Copy to clipboard"
|
title="Copy to clipboard"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ export function ColorPicker({ value, field, label, onChange }: ColorPickerProps)
|
||||||
<Popover className="relative flex items-center">
|
<Popover className="relative flex items-center">
|
||||||
<PopoverButton className="cursor-pointer group focus:outline-none">
|
<PopoverButton className="cursor-pointer group focus:outline-none">
|
||||||
<div
|
<div
|
||||||
className="w-6 h-6 rounded-full border-2 transition-all duration-150 group-hover:scale-110 group-focus-visible:ring-2 group-focus-visible:ring-offset-1"
|
className="w-6 h-6 rounded-full border-2 transition duration-fast group-focus-visible:ring-2 group-focus-visible:ring-offset-1"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: value,
|
backgroundColor: value,
|
||||||
borderColor: isLightColor(value) ? '#00000022' : '#ffffff22',
|
borderColor: isLightColor(value) ? '#00000022' : '#ffffff22',
|
||||||
|
|
@ -92,7 +92,7 @@ export function ColorPicker({ value, field, label, onChange }: ColorPickerProps)
|
||||||
anchor="bottom start"
|
anchor="bottom start"
|
||||||
transition
|
transition
|
||||||
className="z-[60] mt-2 w-56 rounded-xl shadow-xl border border-offbase bg-background p-3 space-y-3
|
className="z-[60] mt-2 w-56 rounded-xl shadow-xl border border-offbase bg-background p-3 space-y-3
|
||||||
transition duration-150 ease-out data-[closed]:opacity-0 data-[closed]:scale-95"
|
transition duration-fast ease-standard data-[closed]:opacity-0 data-[closed]:scale-95"
|
||||||
>
|
>
|
||||||
{/* Label */}
|
{/* Label */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
|
|
@ -107,7 +107,7 @@ export function ColorPicker({ value, field, label, onChange }: ColorPickerProps)
|
||||||
className="p-1"
|
className="p-1"
|
||||||
aria-label="Open system color picker"
|
aria-label="Open system color picker"
|
||||||
>
|
>
|
||||||
<PaletteIcon className="w-4 h-4 text-muted transform transition-transform duration-200 ease-in-out hover:scale-[1.09] hover:text-accent" />
|
<PaletteIcon className="w-4 h-4 text-muted transform transition-transform duration-base ease-standard hover:text-accent" />
|
||||||
</button>
|
</button>
|
||||||
<input
|
<input
|
||||||
ref={nativeRef}
|
ref={nativeRef}
|
||||||
|
|
@ -130,7 +130,7 @@ export function ColorPicker({ value, field, label, onChange }: ColorPickerProps)
|
||||||
key={color}
|
key={color}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onChange(color)}
|
onClick={() => onChange(color)}
|
||||||
className="group/swatch relative w-full aspect-square rounded-full transition-transform duration-100 hover:scale-125 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1"
|
className="group/swatch relative w-full aspect-square rounded-full transition-transform duration-fast focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: color,
|
backgroundColor: color,
|
||||||
boxShadow: selected ? '0 0 0 2px var(--background), 0 0 0 4px var(--foreground)' : undefined,
|
boxShadow: selected ? '0 0 0 2px var(--background), 0 0 0 4px var(--foreground)' : undefined,
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,10 @@ export function ConfirmDialog({
|
||||||
>
|
>
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -55,14 +55,14 @@ export function ConfirmDialog({
|
||||||
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0 scale-95"
|
enterFrom="opacity-0 scale-95"
|
||||||
enterTo="opacity-100 scale-100"
|
enterTo="opacity-100 scale-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100 scale-100"
|
leaveFrom="opacity-100 scale-100"
|
||||||
leaveTo="opacity-0 scale-95"
|
leaveTo="opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<DialogPanel role='dialog' className="w-full max-w-md transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition-all">
|
<DialogPanel role='dialog' className="w-full max-w-md transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition">
|
||||||
<DialogTitle
|
<DialogTitle
|
||||||
as="h3"
|
as="h3"
|
||||||
className="text-lg font-semibold leading-6 text-foreground"
|
className="text-lg font-semibold leading-6 text-foreground"
|
||||||
|
|
@ -79,7 +79,6 @@ export function ConfirmDialog({
|
||||||
className={buttonClass({
|
className={buttonClass({
|
||||||
variant: 'outline',
|
variant: 'outline',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
className: 'hover:scale-[1.04]',
|
|
||||||
})}
|
})}
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
>
|
>
|
||||||
|
|
@ -90,7 +89,7 @@ export function ConfirmDialog({
|
||||||
className={buttonClass({
|
className={buttonClass({
|
||||||
variant: isDangerous ? 'danger' : 'primary',
|
variant: isDangerous ? 'danger' : 'primary',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
className: 'text-wrap hover:scale-[1.04]',
|
className: 'text-wrap',
|
||||||
})}
|
})}
|
||||||
onClick={onConfirm}
|
onClick={onConfirm}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,10 @@ export function CookieConsentBanner() {
|
||||||
<Transition
|
<Transition
|
||||||
as="div"
|
as="div"
|
||||||
show={show}
|
show={show}
|
||||||
enter="transition ease-out duration-300 transform"
|
enter="transition ease-standard duration-slow transform"
|
||||||
enterFrom="translate-y-full opacity-0"
|
enterFrom="translate-y-full opacity-0"
|
||||||
enterTo="translate-y-0 opacity-100"
|
enterTo="translate-y-0 opacity-100"
|
||||||
leave="transition ease-in duration-200 transform"
|
leave="transition ease-standard duration-base transform"
|
||||||
leaveFrom="translate-y-0 opacity-100"
|
leaveFrom="translate-y-0 opacity-100"
|
||||||
leaveTo="translate-y-full opacity-0"
|
leaveTo="translate-y-full opacity-0"
|
||||||
className="fixed bottom-0 left-0 right-0 z-[60] px-4 pt-4 pb-[max(1rem,env(safe-area-inset-bottom))] md:px-6 md:pt-6 md:pb-[max(1.5rem,env(safe-area-inset-bottom))]"
|
className="fixed bottom-0 left-0 right-0 z-[60] px-4 pt-4 pb-[max(1rem,env(safe-area-inset-bottom))] md:px-6 md:pt-6 md:pb-[max(1.5rem,env(safe-area-inset-bottom))]"
|
||||||
|
|
|
||||||
|
|
@ -81,10 +81,10 @@ export function PrivacyModal({ isOpen, onAccept, onDismiss }: PrivacyModalProps)
|
||||||
<Dialog as="div" className="relative z-[80]" onClose={onDismiss ?? (() => { })}>
|
<Dialog as="div" className="relative z-[80]" onClose={onDismiss ?? (() => { })}>
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -95,14 +95,14 @@ export function PrivacyModal({ isOpen, onAccept, onDismiss }: PrivacyModalProps)
|
||||||
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0 scale-95"
|
enterFrom="opacity-0 scale-95"
|
||||||
enterTo="opacity-100 scale-100"
|
enterTo="opacity-100 scale-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100 scale-100"
|
leaveFrom="opacity-100 scale-100"
|
||||||
leaveTo="opacity-0 scale-95"
|
leaveTo="opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<DialogPanel data-testid="privacy-modal" className="w-full max-w-md transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition-all">
|
<DialogPanel data-testid="privacy-modal" className="w-full max-w-md transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition">
|
||||||
<DialogTitle
|
<DialogTitle
|
||||||
as="h3"
|
as="h3"
|
||||||
className="text-lg font-semibold leading-6 text-foreground"
|
className="text-lg font-semibold leading-6 text-foreground"
|
||||||
|
|
@ -143,7 +143,7 @@ export function PrivacyModal({ isOpen, onAccept, onDismiss }: PrivacyModalProps)
|
||||||
font-medium text-background hover:bg-secondary-accent
|
font-medium text-background hover:bg-secondary-accent
|
||||||
disabled:opacity-50 disabled:cursor-not-allowed
|
disabled:opacity-50 disabled:cursor-not-allowed
|
||||||
focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
||||||
transform transition-transform duration-200 ease-in-out enabled:hover:scale-[1.04]"
|
transform transition-transform duration-base ease-standard"
|
||||||
onClick={handleAccept}
|
onClick={handleAccept}
|
||||||
>
|
>
|
||||||
Continue
|
Continue
|
||||||
|
|
@ -195,10 +195,10 @@ export function showPrivacyModal(): void {
|
||||||
<Dialog as="div" className="relative z-50" onClose={handleClose}>
|
<Dialog as="div" className="relative z-50" onClose={handleClose}>
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -209,14 +209,14 @@ export function showPrivacyModal(): void {
|
||||||
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0 scale-95"
|
enterFrom="opacity-0 scale-95"
|
||||||
enterTo="opacity-100 scale-100"
|
enterTo="opacity-100 scale-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100 scale-100"
|
leaveFrom="opacity-100 scale-100"
|
||||||
leaveTo="opacity-0 scale-95"
|
leaveTo="opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<DialogPanel className="w-full max-w-md transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition-all">
|
<DialogPanel className="w-full max-w-md transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition">
|
||||||
<DialogTitle
|
<DialogTitle
|
||||||
as="h3"
|
as="h3"
|
||||||
className="text-lg font-semibold leading-6 text-foreground"
|
className="text-lg font-semibold leading-6 text-foreground"
|
||||||
|
|
@ -232,7 +232,7 @@ export function showPrivacyModal(): void {
|
||||||
className="inline-flex justify-center rounded-lg bg-accent px-4 py-2 text-sm
|
className="inline-flex justify-center rounded-lg bg-accent px-4 py-2 text-sm
|
||||||
font-medium text-background hover:bg-secondary-accent focus:outline-none
|
font-medium text-background hover:bg-secondary-accent focus:outline-none
|
||||||
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
||||||
transform transition-transform duration-200 ease-in-out hover:scale-[1.04]"
|
transform transition-transform duration-base ease-standard"
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
>
|
>
|
||||||
Close
|
Close
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ export function ProgressCard({
|
||||||
className={buttonClass({
|
className={buttonClass({
|
||||||
variant: 'ghost',
|
variant: 'ghost',
|
||||||
size: 'xs',
|
size: 'xs',
|
||||||
className: 'shrink-0 hover:bg-background/50 hover:scale-[1.04]',
|
className: 'shrink-0 hover:bg-background/50',
|
||||||
})}
|
})}
|
||||||
onClick={(e) => onCancel(e)}
|
onClick={(e) => onCancel(e)}
|
||||||
>
|
>
|
||||||
|
|
@ -68,7 +68,7 @@ export function ProgressCard({
|
||||||
{/* Progress bar */}
|
{/* Progress bar */}
|
||||||
<div className="w-full bg-background rounded-full overflow-hidden h-1.5">
|
<div className="w-full bg-background rounded-full overflow-hidden h-1.5">
|
||||||
<div
|
<div
|
||||||
className="h-full bg-accent transition-all duration-300 ease-out"
|
className="h-full bg-accent transition duration-slow ease-standard"
|
||||||
style={{ width: `${progress}%` }}
|
style={{ width: `${progress}%` }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,10 @@ export function ProgressPopup({
|
||||||
<Transition
|
<Transition
|
||||||
show={isOpen}
|
show={isOpen}
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="transform transition ease-out duration-300"
|
enter="transform transition ease-standard duration-slow"
|
||||||
enterFrom="opacity-0 -translate-y-4"
|
enterFrom="opacity-0 -translate-y-4"
|
||||||
enterTo="opacity-100 translate-y-0"
|
enterTo="opacity-100 translate-y-0"
|
||||||
leave="transform transition ease-in duration-200"
|
leave="transform transition ease-standard duration-base"
|
||||||
leaveFrom="opacity-100 translate-y-0"
|
leaveFrom="opacity-100 translate-y-0"
|
||||||
leaveTo="opacity-0 -translate-y-4"
|
leaveTo="opacity-0 -translate-y-4"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -142,11 +142,11 @@ export function SettingsTrigger({
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
onClick={onOpen}
|
onClick={onOpen}
|
||||||
className={`inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase hover:text-accent transition-transform transition-colors duration-200 ease-out hover:scale-[1.01] ${className}`}
|
className={`inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase hover:text-accent transition-transform transition-colors duration-base ease-standard ${className}`}
|
||||||
aria-label="Settings"
|
aria-label="Settings"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<SettingsIcon className="w-4 h-4 transition-transform duration-200 ease-out hover:scale-[1.01] hover:rotate-45" />
|
<SettingsIcon className="w-4 h-4 transition-transform duration-base ease-standard hover:rotate-45" />
|
||||||
{triggerLabel && <span className="ml-2">{triggerLabel}</span>}
|
{triggerLabel && <span className="ml-2">{triggerLabel}</span>}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
@ -519,10 +519,10 @@ export function SettingsModal({
|
||||||
>
|
>
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -533,14 +533,14 @@ export function SettingsModal({
|
||||||
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0 scale-95"
|
enterFrom="opacity-0 scale-95"
|
||||||
enterTo="opacity-100 scale-100"
|
enterTo="opacity-100 scale-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100 scale-100"
|
leaveFrom="opacity-100 scale-100"
|
||||||
leaveTo="opacity-0 scale-95"
|
leaveTo="opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<DialogPanel data-testid="settings-modal" className="relative w-full max-w-4xl transform rounded-xl bg-base text-left align-middle shadow-xl transition-all overflow-hidden border border-offbase">
|
<DialogPanel data-testid="settings-modal" className="relative w-full max-w-4xl transform rounded-xl bg-base text-left align-middle shadow-xl transition overflow-hidden border border-offbase">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between px-5 py-3 border-b border-offbase">
|
<div className="flex items-center justify-between px-5 py-3 border-b border-offbase">
|
||||||
<div className="flex items-baseline gap-4">
|
<div className="flex items-baseline gap-4">
|
||||||
|
|
@ -666,7 +666,7 @@ export function SettingsModal({
|
||||||
</ListboxButton>
|
</ListboxButton>
|
||||||
<Transition
|
<Transition
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
leave="transition ease-in duration-100"
|
leave="transition ease-standard duration-fast"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -782,7 +782,7 @@ export function SettingsModal({
|
||||||
</ListboxButton>
|
</ListboxButton>
|
||||||
<Transition
|
<Transition
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
leave="transition ease-in duration-100"
|
leave="transition ease-standard duration-fast"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -908,7 +908,7 @@ export function SettingsModal({
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
onClick={() => setTheme(systemTheme.id)}
|
onClick={() => setTheme(systemTheme.id)}
|
||||||
className={`flex items-center gap-2 rounded-lg px-2 py-1.5 w-full text-left transition-all duration-200 ease-in-out transform hover:scale-[1.02] border
|
className={`flex items-center gap-2 rounded-lg px-2 py-1.5 w-full text-left transition duration-base ease-standard transform border
|
||||||
${isActive
|
${isActive
|
||||||
? 'border-accent'
|
? 'border-accent'
|
||||||
: 'border-offbase hover:border-muted'
|
: 'border-offbase hover:border-muted'
|
||||||
|
|
@ -952,7 +952,7 @@ export function SettingsModal({
|
||||||
setTheme('custom');
|
setTheme('custom');
|
||||||
setIsCustomExpanded(true);
|
setIsCustomExpanded(true);
|
||||||
}}
|
}}
|
||||||
className={`flex items-center gap-2 rounded-lg px-2 py-1.5 flex-1 text-left transition-all duration-200 ease-in-out transform hover:scale-[1.02] border
|
className={`flex items-center gap-2 rounded-lg px-2 py-1.5 flex-1 text-left transition duration-base ease-standard transform border
|
||||||
${isActive
|
${isActive
|
||||||
? 'border-accent'
|
? 'border-accent'
|
||||||
: 'border-offbase hover:border-muted'
|
: 'border-offbase hover:border-muted'
|
||||||
|
|
@ -984,7 +984,7 @@ export function SettingsModal({
|
||||||
style={{ color: colors.muted, backgroundColor: colors.base }}
|
style={{ color: colors.muted, backgroundColor: colors.base }}
|
||||||
aria-label={isCustomExpanded ? 'Collapse color picker' : 'Expand color picker'}
|
aria-label={isCustomExpanded ? 'Collapse color picker' : 'Expand color picker'}
|
||||||
>
|
>
|
||||||
<svg className={`w-3.5 h-3.5 transition-transform duration-200 ${isCustomExpanded ? 'rotate-180' : ''}`} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
<svg className={`w-3.5 h-3.5 transition-transform duration-base ${isCustomExpanded ? 'rotate-180' : ''}`} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -1052,7 +1052,7 @@ export function SettingsModal({
|
||||||
<button
|
<button
|
||||||
key={t.id}
|
key={t.id}
|
||||||
onClick={() => setTheme(t.id)}
|
onClick={() => setTheme(t.id)}
|
||||||
className={`flex items-center gap-2 rounded-lg px-2 py-1.5 text-left transition-all duration-200 ease-in-out transform hover:scale-[1.02] border
|
className={`flex items-center gap-2 rounded-lg px-2 py-1.5 text-left transition duration-base ease-standard transform border
|
||||||
${isActive
|
${isActive
|
||||||
? 'border-accent'
|
? 'border-accent'
|
||||||
: 'border-offbase hover:border-muted'
|
: 'border-offbase hover:border-muted'
|
||||||
|
|
@ -1094,7 +1094,7 @@ export function SettingsModal({
|
||||||
<button
|
<button
|
||||||
key={t.id}
|
key={t.id}
|
||||||
onClick={() => setTheme(t.id)}
|
onClick={() => setTheme(t.id)}
|
||||||
className={`flex items-center gap-2 rounded-lg px-2 py-1.5 text-left transition-all duration-200 ease-in-out transform hover:scale-[1.02] border
|
className={`flex items-center gap-2 rounded-lg px-2 py-1.5 text-left transition duration-base ease-standard transform border
|
||||||
${isActive
|
${isActive
|
||||||
? 'border-accent'
|
? 'border-accent'
|
||||||
: 'border-offbase hover:border-muted'
|
: 'border-offbase hover:border-muted'
|
||||||
|
|
@ -1247,7 +1247,7 @@ export function SettingsModal({
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleSignOut}
|
onClick={handleSignOut}
|
||||||
className={buttonClass({ variant: 'outline', size: 'md', className: 'hover:scale-[1.04]' })}
|
className={buttonClass({ variant: 'outline', size: 'md' })}
|
||||||
>
|
>
|
||||||
Disconnect account
|
Disconnect account
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -1278,19 +1278,19 @@ export function SettingsModal({
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
<Link href="/signin">
|
<Link href="/signin">
|
||||||
<Button className={buttonClass({ variant: 'outline', size: 'md', className: 'hover:scale-[1.04]' })}>
|
<Button className={buttonClass({ variant: 'outline', size: 'md' })}>
|
||||||
Connect
|
Connect
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
{runtimeConfig.enableUserSignups && (
|
{runtimeConfig.enableUserSignups && (
|
||||||
<Link href="/signup">
|
<Link href="/signup">
|
||||||
<Button className={buttonClass({ variant: 'primary', size: 'md', className: 'hover:scale-[1.04]' })}>
|
<Button className={buttonClass({ variant: 'primary', size: 'md' })}>
|
||||||
Create account
|
Create account
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
<Link href="/?redirect=false">
|
<Link href="/?redirect=false">
|
||||||
<Button className={buttonClass({ variant: 'outline', size: 'md', className: 'hover:scale-[1.04]' })}>
|
<Button className={buttonClass({ variant: 'outline', size: 'md' })}>
|
||||||
Back to landing page
|
Back to landing page
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -1439,7 +1439,7 @@ function SettingsChangelogPanel({
|
||||||
<div className="flex items-center gap-3 px-4 py-3 border-b border-offbase bg-background">
|
<div className="flex items-center gap-3 px-4 py-3 border-b border-offbase bg-background">
|
||||||
<Button
|
<Button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="inline-flex items-center justify-center rounded-md text-muted hover:text-accent hover:bg-base transition-all duration-200 ease-in-out transform hover:scale-[1.01]"
|
className="inline-flex items-center justify-center rounded-md text-muted hover:text-accent hover:bg-base transition duration-base ease-standard transform"
|
||||||
aria-label="Back to settings"
|
aria-label="Back to settings"
|
||||||
title="Back"
|
title="Back"
|
||||||
>
|
>
|
||||||
|
|
@ -1472,7 +1472,7 @@ function SettingsChangelogPanel({
|
||||||
href="https://github.com/richardr1126/openreader/releases"
|
href="https://github.com/richardr1126/openreader/releases"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="inline-flex text-xs font-medium text-accent hover:underline transition-all duration-200 ease-in-out transform hover:scale-[1.02]"
|
className="inline-flex text-xs font-medium text-accent hover:underline transition duration-base ease-standard transform"
|
||||||
>
|
>
|
||||||
Open GitHub Releases
|
Open GitHub Releases
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -1497,7 +1497,7 @@ function SettingsChangelogPanel({
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setExpanded((prev) => ({ ...prev, [entry.tag_name]: !isExpanded }))}
|
onClick={() => setExpanded((prev) => ({ ...prev, [entry.tag_name]: !isExpanded }))}
|
||||||
className="w-full text-left py-2 flex items-center gap-2 hover:bg-base transition-all duration-200 ease-in-out transform hover:scale-[1.01]"
|
className="w-full text-left py-2 flex items-center gap-2 hover:bg-base transition duration-base ease-standard transform"
|
||||||
>
|
>
|
||||||
<ChevronRightIcon
|
<ChevronRightIcon
|
||||||
className={`w-3.5 h-3.5 shrink-0 text-muted transition-transform ${
|
className={`w-3.5 h-3.5 shrink-0 text-muted transition-transform ${
|
||||||
|
|
@ -1542,7 +1542,7 @@ function SettingsChangelogPanel({
|
||||||
href={entry.html_url}
|
href={entry.html_url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="inline-flex text-xs font-medium text-accent hover:underline transition-all duration-200 ease-in-out transform hover:scale-[1.02]"
|
className="inline-flex text-xs font-medium text-accent hover:underline transition duration-base ease-standard transform"
|
||||||
>
|
>
|
||||||
View on GitHub
|
View on GitHub
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -78,10 +78,10 @@ export default function ClaimDataModal({
|
||||||
<Dialog as="div" className="relative z-[80]" onClose={onDismiss}>
|
<Dialog as="div" className="relative z-[80]" onClose={onDismiss}>
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -92,14 +92,14 @@ export default function ClaimDataModal({
|
||||||
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0 scale-95"
|
enterFrom="opacity-0 scale-95"
|
||||||
enterTo="opacity-100 scale-100"
|
enterTo="opacity-100 scale-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100 scale-100"
|
leaveFrom="opacity-100 scale-100"
|
||||||
leaveTo="opacity-0 scale-95"
|
leaveTo="opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<DialogPanel data-testid="claim-modal" className="w-full max-w-md transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition-all">
|
<DialogPanel data-testid="claim-modal" className="w-full max-w-md transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition">
|
||||||
<DialogTitle
|
<DialogTitle
|
||||||
as="h3"
|
as="h3"
|
||||||
className="text-lg font-semibold leading-6 text-foreground mb-4"
|
className="text-lg font-semibold leading-6 text-foreground mb-4"
|
||||||
|
|
@ -135,7 +135,7 @@ export default function ClaimDataModal({
|
||||||
className="inline-flex justify-center rounded-lg bg-background px-3 py-1.5 text-sm
|
className="inline-flex justify-center rounded-lg bg-background px-3 py-1.5 text-sm
|
||||||
font-medium text-foreground hover:bg-offbase focus:outline-none
|
font-medium text-foreground hover:bg-offbase focus:outline-none
|
||||||
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
||||||
transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-accent
|
transform transition-transform duration-base ease-standard hover:text-accent
|
||||||
disabled:opacity-50"
|
disabled:opacity-50"
|
||||||
>
|
>
|
||||||
Dismiss
|
Dismiss
|
||||||
|
|
@ -148,7 +148,7 @@ export default function ClaimDataModal({
|
||||||
className="inline-flex justify-center rounded-lg bg-accent px-3 py-1.5 text-sm
|
className="inline-flex justify-center rounded-lg bg-accent px-3 py-1.5 text-sm
|
||||||
font-medium text-background hover:bg-secondary-accent focus:outline-none
|
font-medium text-background hover:bg-secondary-accent focus:outline-none
|
||||||
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
||||||
transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-background
|
transform transition-transform duration-base ease-standard hover:text-background
|
||||||
disabled:opacity-50"
|
disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isClaiming ? 'Claiming...' : 'Claim Data'}
|
{isClaiming ? 'Claiming...' : 'Claim Data'}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export function RateLimitBanner({ className = '' }: RateLimitBannerProps) {
|
||||||
href="/signup"
|
href="/signup"
|
||||||
className="inline-flex items-center px-2 py-1 text-xs font-medium rounded-md
|
className="inline-flex items-center px-2 py-1 text-xs font-medium rounded-md
|
||||||
bg-accent text-background hover:bg-secondary-accent
|
bg-accent text-background hover:bg-secondary-accent
|
||||||
transform transition-transform duration-200 hover:scale-[1.04]"
|
transform transition-transform duration-base"
|
||||||
>
|
>
|
||||||
Sign up for a higher limit
|
Sign up for a higher limit
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ export function UserMenu({
|
||||||
};
|
};
|
||||||
|
|
||||||
const rowClass =
|
const rowClass =
|
||||||
'w-full inline-flex items-center gap-2 px-2 py-1 rounded-md text-[12px] border border-transparent transition-all duration-200 ease-out text-left hover:scale-[1.01] hover:border-accent hover:bg-offbase hover:text-accent';
|
'w-full inline-flex items-center gap-2 px-2 py-1 rounded-md text-[12px] border border-transparent transition duration-base ease-standard text-left hover:border-accent hover:bg-offbase hover:text-accent';
|
||||||
|
|
||||||
if (!session || session.user.isAnonymous) {
|
if (!session || session.user.isAnonymous) {
|
||||||
if (variant === 'sidebar') {
|
if (variant === 'sidebar') {
|
||||||
|
|
@ -55,13 +55,13 @@ export function UserMenu({
|
||||||
return (
|
return (
|
||||||
<div className={`flex gap-2 ${className}`}>
|
<div className={`flex gap-2 ${className}`}>
|
||||||
<Link href="/signin">
|
<Link href="/signin">
|
||||||
<Button className="inline-flex items-center rounded-md bg-base border border-offbase px-2 py-1 text-xs font-medium text-foreground hover:bg-offbase focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-2 transform transition-all duration-200 ease-in-out hover:scale-[1.01] hover:text-accent">
|
<Button className="inline-flex items-center rounded-md bg-base border border-offbase px-2 py-1 text-xs font-medium text-foreground hover:bg-offbase focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-2 transform transition duration-base ease-standard hover:text-accent">
|
||||||
Connect
|
Connect
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
{enableUserSignups && (
|
{enableUserSignups && (
|
||||||
<Link href="/signup">
|
<Link href="/signup">
|
||||||
<Button className="inline-flex items-center rounded-md bg-accent px-2 py-1 text-xs font-medium text-background hover:bg-secondary-accent focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-2 transform transition-all duration-200 ease-in-out hover:scale-[1.01]">
|
<Button className="inline-flex items-center rounded-md bg-accent px-2 py-1 text-xs font-medium text-background hover:bg-secondary-accent focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-2 transform transition duration-base ease-standard">
|
||||||
Create account
|
Create account
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -97,7 +97,7 @@ export function UserMenu({
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={handleDisconnectAccount}
|
onClick={handleDisconnectAccount}
|
||||||
className="inline-flex items-center text-foreground text-xs hover:text-accent transform transition-all duration-200 ease-in-out hover:scale-[1.01]"
|
className="inline-flex items-center text-foreground text-xs hover:text-accent transform transition duration-base ease-standard"
|
||||||
title="Disconnect account"
|
title="Disconnect account"
|
||||||
>
|
>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,10 @@ export function CreateFolderDialog({
|
||||||
<Dialog as="div" className="relative z-50" onClose={onClose}>
|
<Dialog as="div" className="relative z-50" onClose={onClose}>
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -35,14 +35,14 @@ export function CreateFolderDialog({
|
||||||
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0 scale-95"
|
enterFrom="opacity-0 scale-95"
|
||||||
enterTo="opacity-100 scale-100"
|
enterTo="opacity-100 scale-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100 scale-100"
|
leaveFrom="opacity-100 scale-100"
|
||||||
leaveTo="opacity-0 scale-95"
|
leaveTo="opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<DialogPanel className="w-full max-w-md transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition-all">
|
<DialogPanel className="w-full max-w-md transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition">
|
||||||
<DialogTitle as="h3" className="text-lg font-semibold text-foreground">
|
<DialogTitle as="h3" className="text-lg font-semibold text-foreground">
|
||||||
Create New Folder
|
Create New Folder
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ function SidebarUploadLoader({
|
||||||
strokeDasharray={`${circumference} ${circumference}`}
|
strokeDasharray={`${circumference} ${circumference}`}
|
||||||
strokeDashoffset={dashOffset}
|
strokeDashoffset={dashOffset}
|
||||||
transform={`rotate(-90 ${size / 2} ${size / 2})`}
|
transform={`rotate(-90 ${size / 2} ${size / 2})`}
|
||||||
style={{ transition: 'stroke-dashoffset 200ms ease-out' }}
|
style={{ transition: 'stroke-dashoffset 200ms ease-standard' }}
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -657,7 +657,7 @@ function DocumentListInner({ brand, appActions }: DocumentListInnerProps) {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowHint(false)}
|
onClick={() => setShowHint(false)}
|
||||||
className="h-6 w-6 inline-flex items-center justify-center text-muted hover:text-accent hover:bg-base hover:scale-[1.01] rounded transition-all duration-200 ease-out"
|
className="h-6 w-6 inline-flex items-center justify-center text-muted hover:text-accent hover:bg-base rounded transition duration-base ease-standard"
|
||||||
aria-label="Dismiss hint"
|
aria-label="Dismiss hint"
|
||||||
>
|
>
|
||||||
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
|
|
||||||
|
|
@ -261,7 +261,7 @@ export function DocumentPreview({ doc }: DocumentPreviewProps) {
|
||||||
ref={imageRef}
|
ref={imageRef}
|
||||||
src={imagePreview}
|
src={imagePreview}
|
||||||
alt={`${doc.name} preview`}
|
alt={`${doc.name} preview`}
|
||||||
className={`absolute inset-0 h-full w-full object-cover transition-opacity duration-150 ${isImageReady ? 'opacity-100' : 'opacity-0'}`}
|
className={`absolute inset-0 h-full w-full object-cover transition-opacity duration-fast ${isImageReady ? 'opacity-100' : 'opacity-0'}`}
|
||||||
draggable={false}
|
draggable={false}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
onLoad={() => {
|
onLoad={() => {
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ export function DocumentTile({
|
||||||
data-doc-tile
|
data-doc-tile
|
||||||
aria-selected={isSelected}
|
aria-selected={isSelected}
|
||||||
className={
|
className={
|
||||||
'group relative flex flex-col rounded-md overflow-hidden border transition-all duration-200 ease-out hover:scale-[1.01] ' +
|
'group relative flex flex-col rounded-md overflow-hidden border transition duration-base ease-standard ' +
|
||||||
(isSelected
|
(isSelected
|
||||||
? 'border-accent bg-offbase'
|
? 'border-accent bg-offbase'
|
||||||
: 'border-offbase bg-base hover:bg-offbase hover:border-accent') +
|
: 'border-offbase bg-base hover:bg-offbase hover:border-accent') +
|
||||||
|
|
@ -187,7 +187,7 @@ export function DocumentTile({
|
||||||
{showDeleteButton && (
|
{showDeleteButton && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => onDelete(doc)}
|
onClick={() => onDelete(doc)}
|
||||||
className={`inline-flex items-center justify-center text-muted hover:text-accent hover:bg-base focus:outline-none transition-colors duration-200 ${TRASH_BTN_CLASSES[iconSize]}`}
|
className={`inline-flex items-center justify-center text-muted hover:text-accent hover:bg-base focus:outline-none transition-colors duration-base ${TRASH_BTN_CLASSES[iconSize]}`}
|
||||||
aria-label={`Delete ${doc.name}`}
|
aria-label={`Delete ${doc.name}`}
|
||||||
>
|
>
|
||||||
<svg className={TRASH_ICON_CLASSES[iconSize]} fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className={TRASH_ICON_CLASSES[iconSize]} fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ function GalleryThumb({
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
aria-current={active ? 'true' : undefined}
|
aria-current={active ? 'true' : undefined}
|
||||||
className={
|
className={
|
||||||
'group relative w-[98px] sm:w-[110px] shrink-0 cursor-pointer rounded-lg overflow-hidden border bg-base snap-start transition-all duration-200 ease-out ' +
|
'group relative w-[98px] sm:w-[110px] shrink-0 cursor-pointer rounded-lg overflow-hidden border bg-base snap-start transition duration-base ease-standard ' +
|
||||||
(active
|
(active
|
||||||
? 'border-accent shadow-[0_10px_24px_-18px_rgba(0,0,0,0.85)] -translate-y-0.5'
|
? 'border-accent shadow-[0_10px_24px_-18px_rgba(0,0,0,0.85)] -translate-y-0.5'
|
||||||
: 'border-offbase hover:border-accent hover:-translate-y-0.5') +
|
: 'border-offbase hover:border-accent hover:-translate-y-0.5') +
|
||||||
|
|
@ -106,20 +106,20 @@ function GalleryThumb({
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'px-2 py-1.5 flex items-center gap-1.5 border-t transition-colors duration-200 ' +
|
'px-2 py-1.5 flex items-center gap-1.5 border-t transition-colors duration-base ' +
|
||||||
(active ? 'bg-offbase border-accent' : 'bg-base border-offbase')
|
(active ? 'bg-offbase border-accent' : 'bg-base border-offbase')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<KindIcon
|
<KindIcon
|
||||||
doc={doc}
|
doc={doc}
|
||||||
className={
|
className={
|
||||||
'w-3 h-3 shrink-0 transition-colors duration-200 ' +
|
'w-3 h-3 shrink-0 transition-colors duration-base ' +
|
||||||
(active ? 'text-accent' : 'text-muted')
|
(active ? 'text-accent' : 'text-muted')
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className={
|
className={
|
||||||
'truncate text-[10px] leading-none transition-colors duration-200 ' +
|
'truncate text-[10px] leading-none transition-colors duration-base ' +
|
||||||
(active ? 'text-accent font-medium' : 'text-foreground')
|
(active ? 'text-accent font-medium' : 'text-foreground')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ function HeaderCell({
|
||||||
onSortChange(field, nextDir);
|
onSortChange(field, nextDir);
|
||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
'flex items-center gap-1 px-2 py-1.5 text-[10px] uppercase tracking-wide font-semibold transition-colors duration-200 ease-out hover:text-accent ' +
|
'flex items-center gap-1 px-2 py-1.5 text-[10px] uppercase tracking-wide font-semibold transition-colors duration-base ease-standard hover:text-accent ' +
|
||||||
(active ? 'text-accent' : 'text-muted') +
|
(active ? 'text-accent' : 'text-muted') +
|
||||||
(align === 'right' ? ' justify-end' : '') +
|
(align === 'right' ? ' justify-end' : '') +
|
||||||
' ' +
|
' ' +
|
||||||
|
|
@ -131,7 +131,7 @@ function DocRow({
|
||||||
data-doc-tile
|
data-doc-tile
|
||||||
aria-selected={isSelected}
|
aria-selected={isSelected}
|
||||||
className={
|
className={
|
||||||
'grid grid-cols-[minmax(0,1fr)_44px_72px_104px_28px] sm:grid-cols-[minmax(0,1fr)_56px_96px_140px_32px] items-center text-[12px] border-b border-offbase transition-colors duration-200 ease-out ' +
|
'grid grid-cols-[minmax(0,1fr)_44px_72px_104px_28px] sm:grid-cols-[minmax(0,1fr)_56px_96px_140px_32px] items-center text-[12px] border-b border-offbase transition-colors duration-base ease-standard ' +
|
||||||
(isSelected
|
(isSelected
|
||||||
? 'bg-offbase text-accent'
|
? 'bg-offbase text-accent'
|
||||||
: 'text-foreground hover:bg-offbase') +
|
: 'text-foreground hover:bg-offbase') +
|
||||||
|
|
@ -161,7 +161,7 @@ function DocRow({
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onDeleteDoc(doc);
|
onDeleteDoc(doc);
|
||||||
}}
|
}}
|
||||||
className="h-7 w-7 flex items-center justify-center text-muted hover:text-accent hover:bg-offbase hover:scale-[1.02] rounded transition-all duration-200 ease-out"
|
className="h-7 w-7 flex items-center justify-center text-muted hover:text-accent hover:bg-offbase rounded transition duration-base ease-standard"
|
||||||
aria-label={`Delete ${doc.name}`}
|
aria-label={`Delete ${doc.name}`}
|
||||||
>
|
>
|
||||||
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ function SidebarRow({
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className={
|
className={
|
||||||
'group w-full flex items-center gap-2 px-2 py-1 rounded-md text-[12px] border transform transition-all duration-200 ease-out text-left hover:scale-[1.01] ' +
|
'group w-full flex items-center gap-2 px-2 py-1 rounded-md text-[12px] border transform transition duration-base ease-standard text-left ' +
|
||||||
(active
|
(active
|
||||||
? 'border-accent bg-offbase text-accent'
|
? 'border-accent bg-offbase text-accent'
|
||||||
: 'border-transparent bg-transparent text-foreground hover:border-accent hover:text-accent') +
|
: 'border-transparent bg-transparent text-foreground hover:border-accent hover:text-accent') +
|
||||||
|
|
@ -65,7 +65,7 @@ function SidebarRow({
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={
|
className={
|
||||||
'w-4 h-4 shrink-0 flex items-center justify-center transition-colors duration-200 ' +
|
'w-4 h-4 shrink-0 flex items-center justify-center transition-colors duration-base ' +
|
||||||
(active ? 'text-accent' : 'text-muted group-hover:text-accent')
|
(active ? 'text-accent' : 'text-muted group-hover:text-accent')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
@ -74,7 +74,7 @@ function SidebarRow({
|
||||||
<span className="truncate flex-1">{label}</span>
|
<span className="truncate flex-1">{label}</span>
|
||||||
{typeof count === 'number' && count > 0 && (
|
{typeof count === 'number' && count > 0 && (
|
||||||
<span
|
<span
|
||||||
className={`text-[10px] text-muted tabular-nums transition-transform duration-200 ease-out ${countClassName ?? ''}`}
|
className={`text-[10px] text-muted tabular-nums transition-transform duration-base ease-standard ${countClassName ?? ''}`}
|
||||||
>
|
>
|
||||||
{count}
|
{count}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -272,7 +272,7 @@ export function FinderSidebar({
|
||||||
rightSlot={(
|
rightSlot={(
|
||||||
<Menu as="div" className="relative inline-flex items-center leading-none text-left shrink-0 normal-case tracking-normal font-normal">
|
<Menu as="div" className="relative inline-flex items-center leading-none text-left shrink-0 normal-case tracking-normal font-normal">
|
||||||
<MenuButton
|
<MenuButton
|
||||||
className="inline-flex items-center justify-center h-3.5 w-5 rounded-sm text-muted hover:text-accent transition-colors duration-200 ease-out focus:outline-none"
|
className="inline-flex items-center justify-center h-3.5 w-5 rounded-sm text-muted hover:text-accent transition-colors duration-base ease-standard focus:outline-none"
|
||||||
title="Folder actions"
|
title="Folder actions"
|
||||||
aria-label="Folder actions"
|
aria-label="Folder actions"
|
||||||
>
|
>
|
||||||
|
|
@ -280,10 +280,10 @@ export function FinderSidebar({
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
<Transition
|
<Transition
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="transition ease-out duration-100"
|
enter="transition ease-standard duration-fast"
|
||||||
enterFrom="transform opacity-0 scale-95"
|
enterFrom="transform opacity-0 scale-95"
|
||||||
enterTo="transform opacity-100 scale-100"
|
enterTo="transform opacity-100 scale-100"
|
||||||
leave="transition ease-in duration-75"
|
leave="transition ease-standard duration-fast"
|
||||||
leaveFrom="transform opacity-100 scale-100"
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
leaveTo="transform opacity-0 scale-95"
|
leaveTo="transform opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
|
|
@ -370,7 +370,7 @@ export function FinderSidebar({
|
||||||
onPointerMove={onResizeMove}
|
onPointerMove={onResizeMove}
|
||||||
onPointerUp={onResizeEnd}
|
onPointerUp={onResizeEnd}
|
||||||
onPointerCancel={onResizeEnd}
|
onPointerCancel={onResizeEnd}
|
||||||
className="hidden md:block absolute top-0 right-0 h-full w-1 cursor-col-resize hover:bg-offbase active:bg-accent transition-colors duration-200 ease-out"
|
className="hidden md:block absolute top-0 right-0 h-full w-1 cursor-col-resize hover:bg-offbase active:bg-accent transition-colors duration-base ease-standard"
|
||||||
/>
|
/>
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ const ICON_SIZES: Array<{ value: IconSize; label: string }> = [
|
||||||
|
|
||||||
// Match SettingsModal / UserMenu trigger sizing exactly so all bar buttons share one rhythm.
|
// Match SettingsModal / UserMenu trigger sizing exactly so all bar buttons share one rhythm.
|
||||||
const TOOLBAR_BTN =
|
const TOOLBAR_BTN =
|
||||||
'inline-flex items-center py-1 px-2 rounded-md border bg-base text-xs transition-all duration-200 ease-out hover:scale-[1.01]';
|
'inline-flex items-center py-1 px-2 rounded-md border bg-base text-xs transition duration-base ease-standard';
|
||||||
const TOOLBAR_BTN_INACTIVE =
|
const TOOLBAR_BTN_INACTIVE =
|
||||||
'border-offbase text-foreground hover:text-accent hover:border-accent hover:bg-offbase';
|
'border-offbase text-foreground hover:text-accent hover:border-accent hover:bg-offbase';
|
||||||
const TOOLBAR_BTN_ACTIVE = 'border-accent bg-offbase text-accent';
|
const TOOLBAR_BTN_ACTIVE = 'border-accent bg-offbase text-accent';
|
||||||
|
|
@ -64,7 +64,7 @@ const TOOLBAR_BTN_ACTIVE = 'border-accent bg-offbase text-accent';
|
||||||
// matches the height of a standalone TOOLBAR_BTN.
|
// matches the height of a standalone TOOLBAR_BTN.
|
||||||
const PILL = 'inline-flex items-center rounded-md border border-offbase bg-base p-0.5 gap-0.5 shrink-0';
|
const PILL = 'inline-flex items-center rounded-md border border-offbase bg-base p-0.5 gap-0.5 shrink-0';
|
||||||
const PILL_SEGMENT =
|
const PILL_SEGMENT =
|
||||||
'inline-flex items-center justify-center rounded-[5px] text-xs transition-colors duration-200 ease-out';
|
'inline-flex items-center justify-center rounded-[5px] text-xs transition-colors duration-base ease-standard';
|
||||||
const PILL_SEGMENT_INACTIVE = 'text-muted hover:bg-offbase hover:text-accent';
|
const PILL_SEGMENT_INACTIVE = 'text-muted hover:bg-offbase hover:text-accent';
|
||||||
const PILL_SEGMENT_ACTIVE = 'bg-offbase text-accent';
|
const PILL_SEGMENT_ACTIVE = 'bg-offbase text-accent';
|
||||||
|
|
||||||
|
|
@ -133,7 +133,7 @@ export function FinderToolbar({
|
||||||
</button>
|
</button>
|
||||||
{isIconsToggle && viewMode === 'icons' && (
|
{isIconsToggle && viewMode === 'icons' && (
|
||||||
<div
|
<div
|
||||||
className="absolute top-full left-1/2 z-30 -translate-x-1/2 pt-1 opacity-0 pointer-events-none transition-opacity duration-150 group-hover/icons:opacity-100 group-hover/icons:pointer-events-auto group-focus-within/icons:opacity-100 group-focus-within/icons:pointer-events-auto"
|
className="absolute top-full left-1/2 z-30 -translate-x-1/2 pt-1 opacity-0 pointer-events-none transition-opacity duration-fast group-hover/icons:opacity-100 group-hover/icons:pointer-events-auto group-focus-within/icons:opacity-100 group-focus-within/icons:pointer-events-auto"
|
||||||
>
|
>
|
||||||
<div className={`${PILL} shadow-lg`}>
|
<div className={`${PILL} shadow-lg`}>
|
||||||
{ICON_SIZES.map(({ value: sizeValue, label: sizeLabel }) => {
|
{ICON_SIZES.map(({ value: sizeValue, label: sizeLabel }) => {
|
||||||
|
|
@ -204,7 +204,7 @@ export function FinderToolbar({
|
||||||
|
|
||||||
<div className="flex-1 min-w-0" />
|
<div className="flex-1 min-w-0" />
|
||||||
|
|
||||||
<div className="hidden sm:flex items-center gap-1.5 px-2 py-1 rounded-md bg-background border border-offbase hover:border-accent focus-within:ring-1 focus-within:ring-accent focus-within:border-accent transition-colors duration-200 ease-out w-[160px] md:w-[200px]">
|
<div className="hidden sm:flex items-center gap-1.5 px-2 py-1 rounded-md bg-background border border-offbase hover:border-accent focus-within:ring-1 focus-within:ring-accent focus-within:border-accent transition-colors duration-base ease-standard w-[160px] md:w-[200px]">
|
||||||
<SearchIcon className="w-3.5 h-3.5 text-muted shrink-0" />
|
<SearchIcon className="w-3.5 h-3.5 text-muted shrink-0" />
|
||||||
<input
|
<input
|
||||||
type="search"
|
type="search"
|
||||||
|
|
|
||||||
|
|
@ -69,10 +69,10 @@ export function FinderWindow({
|
||||||
>
|
>
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="transition-opacity duration-150"
|
enter="transition-opacity duration-fast"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
leave="transition-opacity duration-100"
|
leave="transition-opacity duration-fast"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -81,10 +81,10 @@ export function FinderWindow({
|
||||||
<div className="fixed inset-y-0 left-0 flex max-w-full">
|
<div className="fixed inset-y-0 left-0 flex max-w-full">
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="transition-transform duration-200 ease-out"
|
enter="transition-transform duration-base ease-standard"
|
||||||
enterFrom="-translate-x-full"
|
enterFrom="-translate-x-full"
|
||||||
enterTo="translate-x-0"
|
enterTo="translate-x-0"
|
||||||
leave="transition-transform duration-150 ease-in"
|
leave="transition-transform duration-fast ease-standard"
|
||||||
leaveFrom="translate-x-0"
|
leaveFrom="translate-x-0"
|
||||||
leaveTo="-translate-x-full"
|
leaveTo="-translate-x-full"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -140,10 +140,10 @@ export function DexieMigrationModal({
|
||||||
<Dialog as="div" className="relative z-[80]" onClose={() => (closeDisabled ? null : onComplete())}>
|
<Dialog as="div" className="relative z-[80]" onClose={() => (closeDisabled ? null : onComplete())}>
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -154,14 +154,14 @@ export function DexieMigrationModal({
|
||||||
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0 scale-95"
|
enterFrom="opacity-0 scale-95"
|
||||||
enterTo="opacity-100 scale-100"
|
enterTo="opacity-100 scale-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100 scale-100"
|
leaveFrom="opacity-100 scale-100"
|
||||||
leaveTo="opacity-0 scale-95"
|
leaveTo="opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<DialogPanel data-testid="migration-modal" className="w-full max-w-md transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition-all">
|
<DialogPanel data-testid="migration-modal" className="w-full max-w-md transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition">
|
||||||
<DialogTitle as="h3" className="text-lg font-semibold leading-6 text-foreground mb-4">
|
<DialogTitle as="h3" className="text-lg font-semibold leading-6 text-foreground mb-4">
|
||||||
{title}
|
{title}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
|
|
@ -192,7 +192,7 @@ export function DexieMigrationModal({
|
||||||
className="inline-flex justify-center rounded-lg bg-background px-3 py-1.5 text-sm
|
className="inline-flex justify-center rounded-lg bg-background px-3 py-1.5 text-sm
|
||||||
font-medium text-foreground hover:bg-offbase focus:outline-none
|
font-medium text-foreground hover:bg-offbase focus:outline-none
|
||||||
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
||||||
transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-accent
|
transform transition-transform duration-base ease-standard hover:text-accent
|
||||||
disabled:opacity-50"
|
disabled:opacity-50"
|
||||||
>
|
>
|
||||||
Skip
|
Skip
|
||||||
|
|
@ -203,7 +203,7 @@ export function DexieMigrationModal({
|
||||||
className="inline-flex justify-center rounded-lg bg-accent px-3 py-1.5 text-sm
|
className="inline-flex justify-center rounded-lg bg-accent px-3 py-1.5 text-sm
|
||||||
font-medium text-background hover:bg-secondary-accent focus:outline-none
|
font-medium text-background hover:bg-secondary-accent focus:outline-none
|
||||||
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
|
||||||
transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-background
|
transform transition-transform duration-base ease-standard hover:text-background
|
||||||
disabled:opacity-50"
|
disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isUploading ? 'Uploading…' : 'Upload'}
|
{isUploading ? 'Uploading…' : 'Upload'}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ export function DocumentHeaderMenu({
|
||||||
{onOpenSegments && (
|
{onOpenSegments && (
|
||||||
<button
|
<button
|
||||||
onClick={onOpenSegments}
|
onClick={onOpenSegments}
|
||||||
className={`inline-flex items-center py-1 px-2 rounded-md border bg-base text-xs transition-all duration-200 ease-in-out hover:scale-[1.09] ${
|
className={`inline-flex items-center py-1 px-2 rounded-md border bg-base text-xs transition duration-base ease-standard ${
|
||||||
isSegmentsOpen
|
isSegmentsOpen
|
||||||
? 'border-accent text-accent bg-offbase'
|
? 'border-accent text-accent bg-offbase'
|
||||||
: 'border-offbase text-foreground hover:bg-offbase hover:text-accent'
|
: 'border-offbase text-foreground hover:bg-offbase hover:text-accent'
|
||||||
|
|
@ -57,13 +57,13 @@ export function DocumentHeaderMenu({
|
||||||
aria-label={isSegmentsOpen ? 'Hide segments sidebar' : 'Open segments sidebar'}
|
aria-label={isSegmentsOpen ? 'Hide segments sidebar' : 'Open segments sidebar'}
|
||||||
title={isSegmentsOpen ? 'Hide Segments' : 'Segments'}
|
title={isSegmentsOpen ? 'Hide Segments' : 'Segments'}
|
||||||
>
|
>
|
||||||
<ListIcon className="w-4 h-4 transform transition-transform duration-200 ease-in-out hover:scale-[1.09]" />
|
<ListIcon className="w-4 h-4 transform transition-transform duration-base ease-standard" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{showAudiobookExport && onOpenAudiobook && (
|
{showAudiobookExport && onOpenAudiobook && (
|
||||||
<button
|
<button
|
||||||
onClick={onOpenAudiobook}
|
onClick={onOpenAudiobook}
|
||||||
className={`inline-flex items-center py-1 px-2 rounded-md border bg-base text-xs transition-all duration-200 ease-in-out hover:scale-[1.09] ${
|
className={`inline-flex items-center py-1 px-2 rounded-md border bg-base text-xs transition duration-base ease-standard ${
|
||||||
isAudiobookOpen
|
isAudiobookOpen
|
||||||
? 'border-accent text-accent bg-offbase'
|
? 'border-accent text-accent bg-offbase'
|
||||||
: 'border-offbase text-foreground hover:bg-offbase hover:text-accent'
|
: 'border-offbase text-foreground hover:bg-offbase hover:text-accent'
|
||||||
|
|
@ -71,12 +71,12 @@ export function DocumentHeaderMenu({
|
||||||
aria-label={isAudiobookOpen ? 'Hide audiobook export' : 'Open audiobook export'}
|
aria-label={isAudiobookOpen ? 'Hide audiobook export' : 'Open audiobook export'}
|
||||||
title={isAudiobookOpen ? 'Hide Export Audiobook' : 'Export Audiobook'}
|
title={isAudiobookOpen ? 'Hide Export Audiobook' : 'Export Audiobook'}
|
||||||
>
|
>
|
||||||
<DownloadIcon className="w-4 h-4 transform transition-transform duration-200 ease-in-out hover:scale-[1.09]" />
|
<DownloadIcon className="w-4 h-4 transform transition-transform duration-base ease-standard" />
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={onOpenSettings}
|
onClick={onOpenSettings}
|
||||||
className={`inline-flex items-center py-1 px-2 rounded-md border bg-base text-xs transition-all duration-200 ease-in-out hover:scale-[1.09] ${
|
className={`inline-flex items-center py-1 px-2 rounded-md border bg-base text-xs transition duration-base ease-standard ${
|
||||||
isSettingsOpen
|
isSettingsOpen
|
||||||
? 'border-accent text-accent bg-offbase'
|
? 'border-accent text-accent bg-offbase'
|
||||||
: 'border-offbase text-foreground hover:bg-offbase hover:text-accent'
|
: 'border-offbase text-foreground hover:bg-offbase hover:text-accent'
|
||||||
|
|
@ -84,7 +84,7 @@ export function DocumentHeaderMenu({
|
||||||
aria-label={isSettingsOpen ? 'Hide settings' : 'Open settings'}
|
aria-label={isSettingsOpen ? 'Hide settings' : 'Open settings'}
|
||||||
title={isSettingsOpen ? 'Hide Settings' : 'Settings'}
|
title={isSettingsOpen ? 'Hide Settings' : 'Settings'}
|
||||||
>
|
>
|
||||||
<FileSettingsIcon className="w-4 h-4 transform transition-transform duration-200 ease-in-out hover:scale-[1.09]" />
|
<FileSettingsIcon className="w-4 h-4 transform transition-transform duration-base ease-standard" />
|
||||||
</button>
|
</button>
|
||||||
<UserMenu />
|
<UserMenu />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -95,17 +95,17 @@ export function DocumentHeaderMenu({
|
||||||
<div className="sm:hidden flex items-center">
|
<div className="sm:hidden flex items-center">
|
||||||
<Menu as="div" className="relative inline-block text-left">
|
<Menu as="div" className="relative inline-block text-left">
|
||||||
<MenuButton
|
<MenuButton
|
||||||
className="inline-flex items-center justify-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition-all duration-200 ease-in-out hover:scale-[1.09] hover:text-accent focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
|
className="inline-flex items-center justify-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition duration-base ease-standard hover:text-accent focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
|
||||||
title="Menu"
|
title="Menu"
|
||||||
>
|
>
|
||||||
<DotsVerticalIcon className="w-4 h-4 transform transition-transform duration-200 ease-in-out hover:scale-[1.09] hover:text-accent" />
|
<DotsVerticalIcon className="w-4 h-4 transform transition-transform duration-base ease-standard hover:text-accent" />
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
<Transition
|
<Transition
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="transition ease-out duration-100"
|
enter="transition ease-standard duration-fast"
|
||||||
enterFrom="transform opacity-0 scale-95"
|
enterFrom="transform opacity-0 scale-95"
|
||||||
enterTo="transform opacity-100 scale-100"
|
enterTo="transform opacity-100 scale-100"
|
||||||
leave="transition ease-in duration-75"
|
leave="transition ease-standard duration-fast"
|
||||||
leaveFrom="transform opacity-100 scale-100"
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
leaveTo="transform opacity-0 scale-95"
|
leaveTo="transform opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -118,10 +118,10 @@ export function DocumentSelectionModal({
|
||||||
<Dialog as="div" className="relative z-[60]" onClose={onClose}>
|
<Dialog as="div" className="relative z-[60]" onClose={onClose}>
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -132,14 +132,14 @@ export function DocumentSelectionModal({
|
||||||
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
<div className="flex min-h-full items-start justify-center p-4 pt-6 text-center sm:items-center sm:pt-4">
|
||||||
<TransitionChild
|
<TransitionChild
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="ease-out duration-300"
|
enter="ease-standard duration-slow"
|
||||||
enterFrom="opacity-0 scale-95"
|
enterFrom="opacity-0 scale-95"
|
||||||
enterTo="opacity-100 scale-100"
|
enterTo="opacity-100 scale-100"
|
||||||
leave="ease-in duration-200"
|
leave="ease-standard duration-base"
|
||||||
leaveFrom="opacity-100 scale-100"
|
leaveFrom="opacity-100 scale-100"
|
||||||
leaveTo="opacity-0 scale-95"
|
leaveTo="opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<DialogPanel className="w-full max-w-2xl transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition-all flex flex-col h-[80vh]">
|
<DialogPanel className="w-full max-w-2xl transform rounded-2xl bg-base p-6 text-left align-middle shadow-xl transition flex flex-col h-[80vh]">
|
||||||
<DialogTitle
|
<DialogTitle
|
||||||
as="h3"
|
as="h3"
|
||||||
className="text-lg font-semibold leading-6 text-foreground mb-4 flex-shrink-0 flex justify-between items-center"
|
className="text-lg font-semibold leading-6 text-foreground mb-4 flex-shrink-0 flex justify-between items-center"
|
||||||
|
|
|
||||||
|
|
@ -155,9 +155,7 @@ export function DocumentUploader({
|
||||||
noKeyboard: variant === 'overlay'
|
noKeyboard: variant === 'overlay'
|
||||||
});
|
});
|
||||||
|
|
||||||
const containerBase = `group w-full rounded transform transition-all duration-200 ease-in-out ${
|
const containerBase = `group w-full rounded transition duration-base ease-standard ${
|
||||||
variant === 'compact' ? 'hover:scale-[1.01]' : ''
|
|
||||||
} ${
|
|
||||||
isUploading || isConverting ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'
|
isUploading || isConverting ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'
|
||||||
} ${className}`;
|
} ${className}`;
|
||||||
|
|
||||||
|
|
@ -171,7 +169,7 @@ export function DocumentUploader({
|
||||||
: `${
|
: `${
|
||||||
isDragActive
|
isDragActive
|
||||||
? 'border-2 border-dashed border-accent bg-base text-foreground'
|
? 'border-2 border-dashed border-accent bg-base text-foreground'
|
||||||
: 'border-2 border-dashed border-muted bg-transparent text-foreground hover:border-accent hover:bg-base hover:scale-[1.01]'
|
: 'border-2 border-dashed border-muted bg-transparent text-foreground hover:border-accent hover:bg-base'
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
const paddingClass = variant === 'compact' ? 'py-1 px-2 rounded-md' : 'py-5 px-3 rounded-lg';
|
const paddingClass = variant === 'compact' ? 'py-1 px-2 rounded-md' : 'py-5 px-3 rounded-lg';
|
||||||
|
|
@ -219,7 +217,7 @@ export function DocumentUploader({
|
||||||
<input {...getInputProps()} />
|
<input {...getInputProps()} />
|
||||||
{variant === 'compact' ? (
|
{variant === 'compact' ? (
|
||||||
<div className="flex items-center gap-2 text-left w-full min-w-0">
|
<div className="flex items-center gap-2 text-left w-full min-w-0">
|
||||||
<UploadIcon className="w-3.5 h-3.5 text-muted group-hover:text-accent shrink-0 transition-colors duration-200" />
|
<UploadIcon className="w-3.5 h-3.5 text-muted group-hover:text-accent shrink-0 transition-colors duration-base" />
|
||||||
{isUploading ? (
|
{isUploading ? (
|
||||||
<p className="text-[12px] font-medium truncate flex-1">Uploading…</p>
|
<p className="text-[12px] font-medium truncate flex-1">Uploading…</p>
|
||||||
) : isConverting ? (
|
) : isConverting ? (
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ export function ZoomControl({
|
||||||
className={buttonClass({
|
className={buttonClass({
|
||||||
variant: 'ghost',
|
variant: 'ghost',
|
||||||
size: 'icon',
|
size: 'icon',
|
||||||
className: 'h-6 w-6 text-sm leading-none hover:scale-[1.09]',
|
className: 'h-6 w-6 text-sm leading-none',
|
||||||
})}
|
})}
|
||||||
aria-label="Zoom out"
|
aria-label="Zoom out"
|
||||||
>
|
>
|
||||||
|
|
@ -36,7 +36,7 @@ export function ZoomControl({
|
||||||
className={buttonClass({
|
className={buttonClass({
|
||||||
variant: 'ghost',
|
variant: 'ghost',
|
||||||
size: 'icon',
|
size: 'icon',
|
||||||
className: 'h-6 w-6 text-sm leading-none hover:scale-[1.09]',
|
className: 'h-6 w-6 text-sm leading-none',
|
||||||
})}
|
})}
|
||||||
aria-label="Zoom in"
|
aria-label="Zoom in"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ export const inputClass =
|
||||||
'w-full rounded-md bg-background border border-offbase px-2.5 py-1.5 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-accent';
|
'w-full rounded-md bg-background border border-offbase px-2.5 py-1.5 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-accent';
|
||||||
|
|
||||||
export const listboxButtonClass =
|
export const listboxButtonClass =
|
||||||
'relative w-full cursor-pointer rounded-md bg-background border border-offbase py-1.5 pl-2.5 pr-9 text-left text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-accent hover:bg-base transition-transform duration-200 ease-out hover:scale-[1.01]';
|
'relative w-full cursor-pointer rounded-md bg-background border border-offbase py-1.5 pl-2.5 pr-9 text-left text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-accent hover:bg-base transition-colors duration-fast ease-standard';
|
||||||
export const listboxOptionsClass =
|
export const listboxOptionsClass =
|
||||||
'z-50 w-[var(--button-width)] max-h-60 overflow-y-auto overscroll-contain rounded-md bg-background p-1 shadow-lg ring-1 ring-offbase focus:outline-none [--anchor-gap:0.25rem]';
|
'z-50 w-[var(--button-width)] max-h-60 overflow-y-auto overscroll-contain rounded-md bg-background p-1 shadow-lg ring-1 ring-offbase focus:outline-none [--anchor-gap:0.25rem]';
|
||||||
export const listboxOptionClass = (active: boolean) =>
|
export const listboxOptionClass = (active: boolean) =>
|
||||||
|
|
@ -48,10 +48,10 @@ export const listboxOptionClass = (active: boolean) =>
|
||||||
export const segmentedGroupClass =
|
export const segmentedGroupClass =
|
||||||
'grid gap-1 rounded-full border border-offbase bg-background p-1';
|
'grid gap-1 rounded-full border border-offbase bg-background p-1';
|
||||||
export const segmentedButtonClass = (active: boolean) =>
|
export const segmentedButtonClass = (active: boolean) =>
|
||||||
`rounded-full px-2.5 py-1.5 text-xs font-medium transition-colors transition-transform duration-200 ease-out focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${
|
`rounded-full px-2.5 py-1.5 text-xs font-medium transition-colors duration-fast ease-standard focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${
|
||||||
active
|
active
|
||||||
? 'bg-accent text-background hover:scale-[1.01]'
|
? 'bg-accent text-background'
|
||||||
: 'text-muted hover:bg-base hover:text-foreground hover:scale-[1.02]'
|
: 'text-muted hover:bg-base hover:text-foreground'
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
export function Section({
|
export function Section({
|
||||||
|
|
@ -108,7 +108,7 @@ export function Card({
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className={`rounded-lg border border-offbase bg-background px-3 py-2 transition-transform duration-200 ease-out hover:scale-[1.005] ${className}`}>
|
<div className={`rounded-lg border border-offbase bg-background px-3 py-2 transition-colors duration-fast ease-standard ${className}`}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -159,13 +159,13 @@ export function Switch({
|
||||||
aria-describedby={ariaDescribedBy}
|
aria-describedby={ariaDescribedBy}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={() => onChange(!checked)}
|
onClick={() => onChange(!checked)}
|
||||||
className={`relative inline-flex shrink-0 cursor-pointer items-center rounded-full border border-offbase transition-colors duration-200 ease-out focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed ${s.track} ${
|
className={`relative inline-flex shrink-0 cursor-pointer items-center rounded-full border border-offbase transition-colors duration-fast ease-standard focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed ${s.track} ${
|
||||||
checked ? 'bg-accent' : 'bg-offbase'
|
checked ? 'bg-accent' : 'bg-offbase'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className={`pointer-events-none inline-block rounded-full bg-background shadow-sm ring-0 transition-transform duration-200 ease-out ${s.thumb} ${
|
className={`pointer-events-none inline-block rounded-full bg-background shadow-sm ring-0 transition-transform duration-fast ease-standard ${s.thumb} ${
|
||||||
checked ? s.on : s.off
|
checked ? s.on : s.off
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
|
|
@ -194,8 +194,8 @@ export function ToggleRow({
|
||||||
const descId = useId();
|
const descId = useId();
|
||||||
const rowClass =
|
const rowClass =
|
||||||
variant === 'flat'
|
variant === 'flat'
|
||||||
? 'px-0.5 pt-1 pb-2 border-b border-offbase last:border-b-0 transition-transform duration-200 ease-out hover:scale-[1.003]'
|
? 'px-0.5 pt-1 pb-2 border-b border-offbase last:border-b-0 transition-colors duration-fast ease-standard'
|
||||||
: 'rounded-md border border-offbase bg-background px-2.5 py-1.5 transition-transform duration-200 ease-out hover:scale-[1.005]';
|
: 'rounded-md border border-offbase bg-background px-2.5 py-1.5 transition-colors duration-fast ease-standard';
|
||||||
const handleTextToggle = () => {
|
const handleTextToggle = () => {
|
||||||
if (!disabled) onChange(!checked);
|
if (!disabled) onChange(!checked);
|
||||||
};
|
};
|
||||||
|
|
@ -243,7 +243,7 @@ export function CheckItem({
|
||||||
<span
|
<span
|
||||||
id={labelId}
|
id={labelId}
|
||||||
onClick={handleTextToggle}
|
onClick={handleTextToggle}
|
||||||
className={`flex-1 min-w-0 truncate text-xs leading-4 text-foreground select-none transition-colors duration-200 ease-out group-hover:text-accent ${
|
className={`flex-1 min-w-0 truncate text-xs leading-4 text-foreground select-none transition-colors duration-fast ease-standard group-hover:text-accent ${
|
||||||
disabled ? '' : 'cursor-pointer'
|
disabled ? '' : 'cursor-pointer'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ export const Navigator = ({ currentPage, numPages, skipToLocation }: {
|
||||||
<Button
|
<Button
|
||||||
onClick={() => skipToLocation(currentPage - 1, true)}
|
onClick={() => skipToLocation(currentPage - 1, true)}
|
||||||
disabled={currentPage <= 1}
|
disabled={currentPage <= 1}
|
||||||
className="relative p-2 rounded-full text-foreground hover:bg-offbase data-[hover]:bg-offbase data-[active]:bg-offbase transition-all duration-200 focus:outline-none disabled:opacity-50 transform ease-in-out hover:scale-[1.09] hover:text-accent"
|
className="relative p-2 rounded-full text-foreground hover:bg-offbase data-[hover]:bg-offbase data-[active]:bg-offbase transition duration-base focus:outline-none disabled:opacity-50 transform ease-standard hover:text-accent"
|
||||||
aria-label="Previous page"
|
aria-label="Previous page"
|
||||||
>
|
>
|
||||||
<svg className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
<svg className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||||||
|
|
@ -67,7 +67,7 @@ export const Navigator = ({ currentPage, numPages, skipToLocation }: {
|
||||||
{/* Page number popup */}
|
{/* Page number popup */}
|
||||||
<Popover className="relative mb-1">
|
<Popover className="relative mb-1">
|
||||||
<PopoverButton
|
<PopoverButton
|
||||||
className="bg-offbase px-2 py-0.5 rounded-full focus:outline-none cursor-pointer hover:bg-offbase transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-accent"
|
className="bg-offbase px-2 py-0.5 rounded-full focus:outline-none cursor-pointer hover:bg-offbase transform transition-transform duration-base ease-standard hover:text-accent"
|
||||||
onClick={handlePopoverOpen}
|
onClick={handlePopoverOpen}
|
||||||
>
|
>
|
||||||
<p className="text-xs whitespace-nowrap">
|
<p className="text-xs whitespace-nowrap">
|
||||||
|
|
@ -99,7 +99,7 @@ export const Navigator = ({ currentPage, numPages, skipToLocation }: {
|
||||||
<Button
|
<Button
|
||||||
onClick={() => skipToLocation(currentPage + 1, true)}
|
onClick={() => skipToLocation(currentPage + 1, true)}
|
||||||
disabled={currentPage >= (numPages || 1)}
|
disabled={currentPage >= (numPages || 1)}
|
||||||
className="relative p-2 rounded-full text-foreground hover:bg-offbase data-[hover]:bg-offbase data-[active]:bg-offbase transition-all duration-200 focus:outline-none disabled:opacity-50 transform ease-in-out hover:scale-[1.09] hover:text-accent"
|
className="relative p-2 rounded-full text-foreground hover:bg-offbase data-[hover]:bg-offbase data-[active]:bg-offbase transition duration-base focus:outline-none disabled:opacity-50 transform ease-standard hover:text-accent"
|
||||||
aria-label="Next page"
|
aria-label="Next page"
|
||||||
>
|
>
|
||||||
<svg className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
<svg className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ export function RateLimitPauseButton() {
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isPlaying) togglePlay();
|
if (isPlaying) togglePlay();
|
||||||
}}
|
}}
|
||||||
className="relative p-1.5 rounded-md text-foreground hover:bg-offbase transition-all duration-200 focus:outline-none h-8 w-8 flex items-center justify-center transform ease-in-out hover:scale-[1.09] hover:text-accent"
|
className="relative p-1.5 rounded-md text-foreground hover:bg-offbase transition duration-base focus:outline-none h-8 w-8 flex items-center justify-center transform ease-standard hover:text-accent"
|
||||||
aria-label="Pause"
|
aria-label="Pause"
|
||||||
>
|
>
|
||||||
<PauseIcon className="w-5 h-5" />
|
<PauseIcon className="w-5 h-5" />
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ export const SpeedControl = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover className="relative">
|
<Popover className="relative">
|
||||||
<PopoverButton className="flex items-center space-x-0.5 sm:space-x-1 bg-transparent text-foreground text-xs sm:text-sm focus:outline-none cursor-pointer hover:bg-offbase rounded pl-1.5 sm:pl-2 pr-0.5 sm:pr-1 py-0.5 sm:py-1 transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-accent">
|
<PopoverButton className="flex items-center space-x-0.5 sm:space-x-1 bg-transparent text-foreground text-xs sm:text-sm focus:outline-none cursor-pointer hover:bg-offbase rounded pl-1.5 sm:pl-2 pr-0.5 sm:pr-1 py-0.5 sm:py-1 transform transition-transform duration-base ease-standard hover:text-accent">
|
||||||
<SpeedometerIcon className="h-3 w-3 sm:h-3.5 sm:w-3.5" />
|
<SpeedometerIcon className="h-3 w-3 sm:h-3.5 sm:w-3.5" />
|
||||||
<span className="sm:hidden">{compactTriggerLabel}</span>
|
<span className="sm:hidden">{compactTriggerLabel}</span>
|
||||||
<span className="hidden sm:inline">{triggerLabel}</span>
|
<span className="hidden sm:inline">{triggerLabel}</span>
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ export default function TTSPlayer({ currentPage, numPages }: {
|
||||||
{/* Playback Controls */}
|
{/* Playback Controls */}
|
||||||
<Button
|
<Button
|
||||||
onClick={skipBackward}
|
onClick={skipBackward}
|
||||||
className="relative p-1.5 rounded-md text-foreground hover:bg-offbase transition-all duration-200 focus:outline-none disabled:opacity-50 h-8 w-8 flex items-center justify-center transform ease-in-out hover:scale-[1.09] hover:text-accent"
|
className="relative p-1.5 rounded-md text-foreground hover:bg-offbase transition duration-base focus:outline-none disabled:opacity-50 h-8 w-8 flex items-center justify-center transform ease-standard hover:text-accent"
|
||||||
aria-label="Skip backward"
|
aria-label="Skip backward"
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
>
|
>
|
||||||
|
|
@ -60,7 +60,7 @@ export default function TTSPlayer({ currentPage, numPages }: {
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={togglePlay}
|
onClick={togglePlay}
|
||||||
className="relative p-1.5 rounded-md text-foreground hover:bg-offbase transition-all duration-200 focus:outline-none h-8 w-8 flex items-center justify-center transform ease-in-out hover:scale-[1.09] hover:text-accent"
|
className="relative p-1.5 rounded-md text-foreground hover:bg-offbase transition duration-base focus:outline-none h-8 w-8 flex items-center justify-center transform ease-standard hover:text-accent"
|
||||||
aria-label={isPlaying ? 'Pause' : 'Play'}
|
aria-label={isPlaying ? 'Pause' : 'Play'}
|
||||||
disabled={isProcessing && !isPlaying}
|
disabled={isProcessing && !isPlaying}
|
||||||
>
|
>
|
||||||
|
|
@ -69,7 +69,7 @@ export default function TTSPlayer({ currentPage, numPages }: {
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={skipForward}
|
onClick={skipForward}
|
||||||
className="relative p-1.5 rounded-md text-foreground hover:bg-offbase transition-all duration-200 focus:outline-none disabled:opacity-50 h-8 w-8 flex items-center justify-center transform ease-in-out hover:scale-[1.09] hover:text-accent"
|
className="relative p-1.5 rounded-md text-foreground hover:bg-offbase transition duration-base focus:outline-none disabled:opacity-50 h-8 w-8 flex items-center justify-center transform ease-standard hover:text-accent"
|
||||||
aria-label="Skip forward"
|
aria-label="Skip forward"
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ export function VoicesControlBase({
|
||||||
: 'bottom-full right-0 mb-1';
|
: 'bottom-full right-0 mb-1';
|
||||||
|
|
||||||
const buttonClass = variant === 'field'
|
const buttonClass = variant === 'field'
|
||||||
? 'relative cursor-pointer rounded-lg bg-base py-1.5 pl-3 pr-10 text-left text-foreground focus:outline-none focus:ring-2 focus:ring-accent transform transition-transform duration-200 ease-in-out hover:scale-[1.01] hover:text-accent w-full'
|
? 'relative cursor-pointer rounded-lg bg-base py-1.5 pl-3 pr-10 text-left text-foreground focus:outline-none focus:ring-2 focus:ring-accent transform transition-transform duration-base ease-standard hover:text-accent w-full'
|
||||||
: 'flex items-center space-x-0.5 sm:space-x-1 bg-transparent text-foreground text-xs sm:text-sm focus:outline-none cursor-pointer hover:bg-offbase rounded pl-1.5 sm:pl-2 pr-0.5 sm:pr-1 py-0.5 sm:py-1 transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-accent';
|
: 'flex items-center space-x-0.5 sm:space-x-1 bg-transparent text-foreground text-xs sm:text-sm focus:outline-none cursor-pointer hover:bg-offbase rounded pl-1.5 sm:pl-2 pr-0.5 sm:pr-1 py-0.5 sm:py-1 transform transition-transform duration-base ease-standard hover:text-accent';
|
||||||
|
|
||||||
const iconClass = variant === 'field'
|
const iconClass = variant === 'field'
|
||||||
? 'h-3.5 w-3.5 shrink-0'
|
? 'h-3.5 w-3.5 shrink-0'
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,10 @@ export function ReaderSidebarShell({
|
||||||
>
|
>
|
||||||
<Transition.Child
|
<Transition.Child
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="transition-opacity ease-out duration-200"
|
enter="transition-opacity ease-standard duration-base"
|
||||||
enterFrom="opacity-0"
|
enterFrom="opacity-0"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
leave="transition-opacity ease-in duration-150"
|
leave="transition-opacity ease-standard duration-fast"
|
||||||
leaveFrom="opacity-100"
|
leaveFrom="opacity-100"
|
||||||
leaveTo="opacity-0"
|
leaveTo="opacity-0"
|
||||||
>
|
>
|
||||||
|
|
@ -58,10 +58,10 @@ export function ReaderSidebarShell({
|
||||||
|
|
||||||
<Transition.Child
|
<Transition.Child
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="transition ease-out duration-220"
|
enter="transition ease-standard duration-base"
|
||||||
enterFrom="translate-x-full"
|
enterFrom="translate-x-full"
|
||||||
enterTo="translate-x-0"
|
enterTo="translate-x-0"
|
||||||
leave="transition ease-in duration-180"
|
leave="transition ease-standard duration-base"
|
||||||
leaveFrom="translate-x-0"
|
leaveFrom="translate-x-0"
|
||||||
leaveTo="translate-x-full"
|
leaveTo="translate-x-full"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -901,10 +901,10 @@ function SegmentMetadataPopover({ row }: { row: TTSSegmentRow }) {
|
||||||
</PopoverButton>
|
</PopoverButton>
|
||||||
<Transition
|
<Transition
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="transition ease-out duration-150"
|
enter="transition ease-standard duration-fast"
|
||||||
enterFrom="opacity-0 translate-y-1"
|
enterFrom="opacity-0 translate-y-1"
|
||||||
enterTo="opacity-100 translate-y-0"
|
enterTo="opacity-100 translate-y-0"
|
||||||
leave="transition ease-in duration-100"
|
leave="transition ease-standard duration-fast"
|
||||||
leaveFrom="opacity-100 translate-y-0"
|
leaveFrom="opacity-100 translate-y-0"
|
||||||
leaveTo="opacity-0 translate-y-1"
|
leaveTo="opacity-0 translate-y-1"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
export const btnBase =
|
export const btnBase =
|
||||||
'inline-flex items-center justify-center rounded-md text-sm font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 transition-colors transition-transform duration-200 ease-out disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100';
|
'inline-flex items-center justify-center rounded-md text-sm font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 transition-colors duration-fast ease-standard disabled:opacity-50 disabled:cursor-not-allowed';
|
||||||
export const btnPrimary = `${btnBase} bg-accent text-background hover:bg-secondary-accent hover:scale-[1.03]`;
|
export const btnPrimary = `${btnBase} bg-accent text-background hover:bg-secondary-accent`;
|
||||||
export const btnSecondary = `${btnBase} bg-base text-foreground border border-offbase hover:bg-offbase hover:scale-[1.03]`;
|
export const btnSecondary = `${btnBase} bg-base text-foreground border border-offbase hover:bg-offbase`;
|
||||||
export const btnOutline = `${btnBase} bg-background border border-offbase text-foreground hover:bg-base hover:text-accent hover:scale-[1.02]`;
|
export const btnOutline = `${btnBase} bg-background border border-offbase text-foreground hover:bg-base hover:text-accent`;
|
||||||
export const btnDanger = `${btnBase} bg-red-600 text-white border border-red-700 hover:bg-red-700 hover:scale-[1.02]`;
|
export const btnDanger = `${btnBase} bg-danger text-background border border-danger hover:bg-danger`;
|
||||||
export const btnGhost = `${btnBase} bg-transparent text-foreground hover:bg-base hover:text-accent`;
|
export const btnGhost = `${btnBase} bg-transparent text-foreground hover:bg-base hover:text-accent`;
|
||||||
|
|
||||||
export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'danger' | 'ghost';
|
export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'danger' | 'ghost';
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ export function EPUBViewer({ className = '', epubState }: EPUBViewerProps) {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setIsTocOpen(open => !open)}
|
onClick={() => setIsTocOpen(open => !open)}
|
||||||
className="inline-flex items-center py-1 px-1 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition-all duration-200 ease-in-out transform hover:scale-[1.09] hover:text-accent"
|
className="inline-flex items-center py-1 px-1 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition duration-base ease-standard transform hover:text-accent"
|
||||||
aria-label={isTocOpen ? 'Hide chapters' : 'Show chapters'}
|
aria-label={isTocOpen ? 'Hide chapters' : 'Show chapters'}
|
||||||
>
|
>
|
||||||
<DotsVerticalIcon className="w-4 h-4" />
|
<DotsVerticalIcon className="w-4 h-4" />
|
||||||
|
|
@ -171,7 +171,7 @@ export function EPUBViewer({ className = '', epubState }: EPUBViewerProps) {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleLocationChanged('prev')}
|
onClick={() => handleLocationChanged('prev')}
|
||||||
className="inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition-all duration-200 ease-in-out transform hover:scale-[1.09] hover:text-accent"
|
className="inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition duration-base ease-standard transform hover:text-accent"
|
||||||
aria-label="Previous section"
|
aria-label="Previous section"
|
||||||
>
|
>
|
||||||
<ChevronLeftIcon className="w-4 h-4" />
|
<ChevronLeftIcon className="w-4 h-4" />
|
||||||
|
|
@ -185,7 +185,7 @@ export function EPUBViewer({ className = '', epubState }: EPUBViewerProps) {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleLocationChanged('next')}
|
onClick={() => handleLocationChanged('next')}
|
||||||
className="inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition-all duration-200 ease-in-out transform hover:scale-[1.09] hover:text-accent"
|
className="inline-flex items-center py-1 px-2 rounded-md border border-offbase bg-base text-foreground text-xs hover:bg-offbase transition duration-base ease-standard transform hover:text-accent"
|
||||||
aria-label="Next section"
|
aria-label="Next section"
|
||||||
>
|
>
|
||||||
<ChevronRightIcon className="w-4 h-4" />
|
<ChevronRightIcon className="w-4 h-4" />
|
||||||
|
|
@ -205,7 +205,7 @@ export function EPUBViewer({ className = '', epubState }: EPUBViewerProps) {
|
||||||
}}
|
}}
|
||||||
className="
|
className="
|
||||||
px-2 py-1 rounded-md font-medium text-foreground text-center bg-base
|
px-2 py-1 rounded-md font-medium text-foreground text-center bg-base
|
||||||
hover:bg-offbase hover:text-accent transition-colors duration-150
|
hover:bg-offbase hover:text-accent transition-colors duration-fast
|
||||||
whitespace-nowrap
|
whitespace-nowrap
|
||||||
flex-1 min-w-[140px]
|
flex-1 min-w-[140px]
|
||||||
"
|
"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue