Slave/ui polishing #13
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="flex min-h-screen flex-col bg-background">
|
||||
<div class="flex min-h-screen w-full min-w-0 flex-col overflow-x-clip bg-background">
|
||||
<AppHeader />
|
||||
<div class="flex min-h-0 flex-1 flex-col">
|
||||
<div class="flex min-h-0 min-w-0 flex-1 flex-col overflow-x-clip">
|
||||
<router-view />
|
||||
</div>
|
||||
<AppFooter />
|
||||
|
||||
@@ -50,8 +50,16 @@
|
||||
@apply border-border;
|
||||
}
|
||||
|
||||
html {
|
||||
@apply w-full min-w-0 overflow-x-hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-background text-foreground antialiased;
|
||||
@apply min-w-0 overflow-x-hidden bg-background text-foreground antialiased;
|
||||
}
|
||||
|
||||
#app {
|
||||
@apply w-full min-w-0 overflow-x-clip;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +79,8 @@ body:has(.lightbox:target) {
|
||||
z-index: 100;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 1.5rem;
|
||||
padding: max(0.75rem, env(safe-area-inset-top)) max(0.75rem, env(safe-area-inset-right))
|
||||
max(0.75rem, env(safe-area-inset-bottom)) max(0.75rem, env(safe-area-inset-left));
|
||||
}
|
||||
|
||||
.lightbox:target {
|
||||
@@ -87,8 +96,8 @@ body:has(.lightbox:target) {
|
||||
.lightbox__img {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
max-width: min(95vw, 75rem);
|
||||
max-height: 90vh;
|
||||
max-width: min(100%, 75rem);
|
||||
max-height: min(85dvh, 90vh);
|
||||
width: auto;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
@@ -98,8 +107,8 @@ body:has(.lightbox:target) {
|
||||
|
||||
.lightbox__close {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
top: max(0.5rem, env(safe-area-inset-top));
|
||||
right: max(0.5rem, env(safe-area-inset-right));
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="expandable-image">
|
||||
<div class="expandable-image min-w-0">
|
||||
<figure class="m-0">
|
||||
<a
|
||||
:href="`#${lightboxId}`"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="inline-flex w-fit rounded-md border border-border p-0.5">
|
||||
<div class="flex w-full rounded-md border border-border p-0.5 sm:inline-flex sm:w-fit">
|
||||
<button
|
||||
v-for="option in options"
|
||||
:key="option.value"
|
||||
type="button"
|
||||
class="rounded px-3 py-1.5 text-xs font-medium transition-colors"
|
||||
class="min-w-0 flex-1 rounded px-3 py-1.5 text-center text-xs font-medium transition-colors sm:flex-none"
|
||||
:class="
|
||||
modelValue === option.value
|
||||
? 'bg-muted text-foreground'
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
<template>
|
||||
<div class="overflow-x-auto rounded-lg border border-border">
|
||||
<div
|
||||
class="max-w-full overflow-x-auto rounded-lg border border-border contain-[layout_paint_style]"
|
||||
>
|
||||
<table class="w-full min-w-160 border-collapse text-left text-sm">
|
||||
<thead>
|
||||
<tr class="border-b border-border bg-muted/40">
|
||||
<th class="sticky left-0 z-10 min-w-48 bg-muted/40 px-3 py-2.5 font-medium text-foreground">
|
||||
<tr class="border-b border-border bg-muted">
|
||||
<th class="sticky left-0 z-10 min-w-48 bg-muted px-3 py-2.5 font-medium text-foreground">
|
||||
Feature
|
||||
</th>
|
||||
<th
|
||||
v-for="host in comparisonHosts"
|
||||
:key="host.id"
|
||||
class="min-w-38 px-3 py-2.5 font-medium"
|
||||
class="min-w-38 bg-muted px-3 py-2.5 font-medium"
|
||||
:class="host.id === 'privateImage' ? 'bg-primary/5 text-foreground' : 'text-muted-foreground'"
|
||||
>
|
||||
{{ host.name }}
|
||||
@@ -19,7 +21,7 @@
|
||||
<tbody class="text-muted-foreground">
|
||||
<tr v-for="row in comparisonRows" :key="row.feature" class="border-b border-border last:border-0">
|
||||
<td
|
||||
class="sticky left-0 z-10 bg-card px-3 py-2.5 font-medium text-foreground shadow-[1px_0_0_0_var(--border)]"
|
||||
class="sticky left-0 z-10 bg-background px-3 py-2.5 font-medium text-foreground shadow-[1px_0_0_0_var(--border)]"
|
||||
>
|
||||
{{ row.feature }}
|
||||
</td>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<footer class="mt-auto border-t border-border bg-card">
|
||||
<div
|
||||
class="mx-auto flex max-w-5xl flex-col items-center gap-2 px-4 py-5 text-center text-xs text-muted-foreground sm:px-6 sm:text-sm"
|
||||
class="mx-auto flex max-w-5xl flex-col items-center gap-2 px-3 py-4 text-center text-xs text-muted-foreground sm:px-6 sm:py-5 sm:text-sm"
|
||||
>
|
||||
<p class="flex flex-wrap items-center justify-center gap-x-2 gap-y-1">
|
||||
<a
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<header class="border-b border-border bg-card">
|
||||
<div class="mx-auto flex h-14 max-w-5xl items-center justify-between gap-4 px-4 sm:px-6">
|
||||
<div class="mx-auto flex h-14 max-w-5xl items-center justify-between gap-2 px-3 sm:gap-4 sm:px-6">
|
||||
<RouterLink
|
||||
:to="{ name: ROUTE_NAMES.Upload }"
|
||||
class="shrink-0 transition-opacity hover:opacity-80"
|
||||
class="min-w-0 shrink transition-opacity hover:opacity-80"
|
||||
>
|
||||
<img
|
||||
src="/logo.png"
|
||||
alt="Private Image"
|
||||
class="h-8 w-auto sm:h-9"
|
||||
class="h-7 w-auto max-w-[min(100%,12rem)] sm:h-8 md:h-9"
|
||||
width="1024"
|
||||
height="228"
|
||||
decoding="async"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<section class="flex min-h-48 flex-col rounded-lg border border-border bg-card">
|
||||
<header class="border-b border-border px-4 py-3">
|
||||
<header class="border-b border-border px-3 py-2.5 sm:px-4 sm:py-3">
|
||||
<h2 class="text-sm font-medium text-card-foreground">Metadata Inspector</h2>
|
||||
<p v-if="fileName" class="mt-0.5 truncate text-xs text-muted-foreground">{{ fileName }}</p>
|
||||
</header>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<pre
|
||||
class="max-h-96 min-h-32 flex-1 overflow-auto rounded-md bg-muted p-3 text-xs leading-relaxed whitespace-pre-wrap text-foreground"
|
||||
class="max-h-96 min-h-32 flex-1 overflow-auto rounded-md bg-muted p-3 text-xs leading-relaxed break-all whitespace-pre-wrap text-foreground"
|
||||
><slot /></pre>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<label class="flex flex-col gap-1.5 text-xs">
|
||||
<span class="font-medium text-muted-foreground">{{ label }}</span>
|
||||
<div class="flex gap-2">
|
||||
<div class="flex flex-col gap-2 sm:flex-row">
|
||||
<input
|
||||
type="text"
|
||||
readonly
|
||||
@@ -10,7 +10,7 @@
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="shrink-0 rounded-md border border-border px-3 py-2 text-xs font-medium transition-colors hover:bg-muted/60"
|
||||
class="shrink-0 rounded-md border border-border px-3 py-2.5 text-xs font-medium transition-colors hover:bg-muted/60 sm:py-2"
|
||||
@click="onCopyClick"
|
||||
>
|
||||
{{ copied ? 'Copied' : 'Copy' }}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<div v-if="open" class="fixed inset-0 z-50 flex items-end justify-center bg-black/50 p-4 sm:items-center">
|
||||
<div v-if="open" class="fixed inset-0 z-50 flex items-end justify-center overflow-y-auto bg-black/50 p-4 sm:items-center">
|
||||
<div class="flex w-full max-w-lg flex-col rounded-lg border border-border bg-card shadow-lg">
|
||||
<header class="border-b border-border px-4 py-3">
|
||||
<h2 class="text-base font-medium text-card-foreground">
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
<div
|
||||
v-if="open && metadataErrorConfirmOpen"
|
||||
class="fixed inset-0 z-60 flex items-end justify-center bg-black/50 p-4 sm:items-center"
|
||||
class="fixed inset-0 z-60 flex items-end justify-center overflow-y-auto bg-black/50 p-4 sm:items-center"
|
||||
>
|
||||
<div class="flex w-full max-w-md flex-col rounded-lg border border-border bg-card shadow-lg">
|
||||
<header class="border-b border-border px-4 py-3">
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div class="flex w-full flex-col gap-3">
|
||||
<p class="mb-3 text-base text-muted-foreground">
|
||||
<p class="text-sm text-muted-foreground sm:text-base">
|
||||
Drop anywhere, paste or choose files. Max {{ maxQueueSize }} images, up to {{ maxImageSizeLabel }} each.
|
||||
</p>
|
||||
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<label
|
||||
class="inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:opacity-90"
|
||||
class="inline-flex w-full items-center justify-center rounded-md bg-primary px-4 py-2.5 text-sm font-medium text-primary-foreground transition-colors hover:opacity-90 sm:w-auto"
|
||||
:class="disabled ? 'cursor-not-allowed opacity-60' : 'cursor-pointer'"
|
||||
>
|
||||
Choose images
|
||||
@@ -24,7 +24,7 @@
|
||||
<button
|
||||
v-if="!uploadConfirmed"
|
||||
type="button"
|
||||
class="inline-flex shrink-0 items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
class="inline-flex w-full shrink-0 items-center justify-center rounded-md bg-primary px-4 py-2.5 text-sm font-medium text-primary-foreground transition-colors hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-60 sm:w-auto"
|
||||
:disabled="!canOpenConfigure"
|
||||
@click="configureModalOpen = true"
|
||||
>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<li v-for="row in rows" :key="row.key">
|
||||
<button
|
||||
type="button"
|
||||
class="flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-muted/60"
|
||||
class="flex w-full items-start gap-3 px-3 py-3 text-left transition-colors hover:bg-muted/60 sm:items-center sm:px-4"
|
||||
:class="isRowSelected(row) ? 'bg-muted/80' : ''"
|
||||
@click="emit('select', row.file)"
|
||||
>
|
||||
@@ -19,16 +19,22 @@
|
||||
class="h-10 w-10 shrink-0 rounded border border-border bg-muted/60"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span class="min-w-0 flex-1 truncate text-sm font-medium">{{ row.file.name }}</span>
|
||||
<div class="min-w-0 flex-1 space-y-1">
|
||||
<div class="flex min-w-0 items-baseline justify-between gap-2">
|
||||
<span class="min-w-0 truncate text-sm font-medium">{{ row.file.name }}</span>
|
||||
<span class="shrink-0 text-xs text-muted-foreground">
|
||||
{{ prettyBytes(row.file.size, { maximumFractionDigits: 1 }) }}
|
||||
</span>
|
||||
<span class="shrink-0 max-w-32 truncate text-xs sm:max-w-40" :class="metadataStatusClass(row.metadata)">
|
||||
</div>
|
||||
<div class="flex min-w-0 flex-col gap-0.5 text-xs sm:flex-row sm:flex-wrap sm:gap-x-3">
|
||||
<span class="min-w-0 truncate" :class="metadataStatusClass(row.metadata)">
|
||||
{{ row.metadata.message }}
|
||||
</span>
|
||||
<span class="shrink-0 max-w-32 truncate text-xs sm:max-w-40" :class="uploadStatusClass(row.upload)">
|
||||
<span class="min-w-0 truncate" :class="uploadStatusClass(row.upload)">
|
||||
{{ row.upload.message }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -52,12 +52,12 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
<label class="flex flex-col gap-1.5 text-sm">
|
||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<label class="flex min-w-0 flex-col gap-1.5 text-sm">
|
||||
<span class="font-medium">Expiry</span>
|
||||
<select
|
||||
v-model="settings.expiryPreset"
|
||||
class="rounded-md border border-input bg-background px-3 py-2 text-sm"
|
||||
class="w-full rounded-md border border-input bg-background px-3 py-2 text-base"
|
||||
>
|
||||
<option v-for="option in expiryOptions" :key="option.value" :value="option.value">
|
||||
{{ option.label }}
|
||||
@@ -65,11 +65,11 @@
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label class="flex flex-col gap-1.5 text-sm">
|
||||
<label class="flex min-w-0 flex-col gap-1.5 text-sm">
|
||||
<span class="font-medium">Max views</span>
|
||||
<select
|
||||
v-model="settings.maxViewsPreset"
|
||||
class="rounded-md border border-input bg-background px-3 py-2 text-sm"
|
||||
class="w-full rounded-md border border-input bg-background px-3 py-2 text-base"
|
||||
>
|
||||
<option v-for="option in maxViewsOptions" :key="option.value" :value="option.value">
|
||||
{{ option.label }}
|
||||
@@ -92,7 +92,7 @@
|
||||
v-model="settings.password"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
class="rounded-md border border-input bg-background px-3 py-2 text-sm"
|
||||
class="rounded-md border border-input bg-background px-3 py-2 text-base"
|
||||
/>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<section class="flex min-h-48 flex-col rounded-lg border border-border bg-card">
|
||||
<header class="border-b border-border px-4 py-3">
|
||||
<header class="border-b border-border px-3 py-2.5 sm:px-4 sm:py-3">
|
||||
<h2 class="text-sm font-medium text-card-foreground">Share links</h2>
|
||||
<p v-if="fileName" class="mt-0.5 truncate text-xs text-muted-foreground">{{ fileName }}</p>
|
||||
</header>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<main class="mx-auto max-w-5xl flex-1 px-4 py-8 sm:px-6">
|
||||
<main class="mx-auto flex w-full min-w-0 max-w-5xl flex-1 flex-col overflow-x-hidden px-4 py-6 sm:px-6 sm:py-8">
|
||||
<article>
|
||||
<h1 class="text-2xl font-semibold tracking-tight sm:text-3xl">About Private Image</h1>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<section id="exiftool" class="mt-14 scroll-mt-20">
|
||||
<section id="exiftool" class="mt-14 scroll-mt-16 sm:scroll-mt-20">
|
||||
<h2 class="text-lg font-medium text-foreground">ExifTool runs in your browser</h2>
|
||||
<p class="mt-3 text-sm leading-relaxed text-muted-foreground sm:text-base sm:leading-relaxed">
|
||||
Private Image uses ExifTool, a widely used metadata tool normally run on a desktop, compiled to work in
|
||||
@@ -45,10 +45,10 @@
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section id="share-modes" class="mt-14 scroll-mt-20">
|
||||
<section id="share-modes" class="mt-14 scroll-mt-16 sm:scroll-mt-20">
|
||||
<h2 class="text-lg font-medium text-foreground">Share modes</h2>
|
||||
|
||||
<h3 id="zero-knowledge" class="mt-6 scroll-mt-20 text-base font-medium text-foreground">
|
||||
<h3 id="zero-knowledge" class="mt-6 scroll-mt-16 sm:scroll-mt-20 text-base font-medium text-foreground">
|
||||
Zero knowledge
|
||||
</h3>
|
||||
<p class="mt-2 text-sm leading-relaxed text-muted-foreground sm:text-base sm:leading-relaxed">
|
||||
@@ -73,7 +73,7 @@
|
||||
expand-label="View larger zero knowledge flow diagram"
|
||||
/>
|
||||
|
||||
<h3 id="hotlink" class="mt-8 scroll-mt-20 text-base font-medium text-foreground">Hotlink</h3>
|
||||
<h3 id="hotlink" class="mt-8 scroll-mt-16 sm:scroll-mt-20 text-base font-medium text-foreground">Hotlink</h3>
|
||||
<p class="mt-2 text-sm leading-relaxed text-muted-foreground sm:text-base sm:leading-relaxed">
|
||||
Hotlink mode keeps images encrypted at rest but decrypts them on the server when they're requested. This
|
||||
makes it possible to embed images directly in forum posts, chats, wikis, and other places that support
|
||||
@@ -109,7 +109,7 @@
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section id="crypto-shred" class="mt-14 scroll-mt-20">
|
||||
<section id="crypto-shred" class="mt-14 scroll-mt-16 sm:scroll-mt-20">
|
||||
<h2 class="text-lg font-medium text-foreground">Crypto-shredding</h2>
|
||||
<p class="mt-3 text-sm leading-relaxed text-muted-foreground sm:text-base sm:leading-relaxed">
|
||||
Deleting a file doesn't always mean every copy of its data has disappeared from a storage device.
|
||||
@@ -137,7 +137,7 @@
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section id="limits" class="mt-14 scroll-mt-20">
|
||||
<section id="limits" class="mt-14 scroll-mt-16 sm:scroll-mt-20">
|
||||
<h2 class="text-lg font-medium text-foreground">Set your own limits</h2>
|
||||
<p class="mt-3 text-sm leading-relaxed text-muted-foreground sm:text-base sm:leading-relaxed">
|
||||
Choose how long each upload stays available, from a short, fixed period to no expiry. You can also limit
|
||||
@@ -148,7 +148,7 @@
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section id="self-hosting" class="mt-14 scroll-mt-20">
|
||||
<section id="self-hosting" class="mt-14 scroll-mt-16 sm:scroll-mt-20">
|
||||
<h2 class="text-lg font-medium text-foreground">Self-hosting</h2>
|
||||
<p class="mt-3 text-sm leading-relaxed text-muted-foreground sm:text-base sm:leading-relaxed">
|
||||
Private Image is open source, so you can run your own instance on hardware you control instead of
|
||||
@@ -162,7 +162,7 @@
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section id="clearnet-and-onion" class="mt-14 scroll-mt-20">
|
||||
<section id="clearnet-and-onion" class="mt-14 scroll-mt-16 sm:scroll-mt-20">
|
||||
<h2 class="text-lg font-medium text-foreground">Clearnet and onion access</h2>
|
||||
<p class="mt-3 text-sm leading-relaxed text-muted-foreground sm:text-base sm:leading-relaxed">
|
||||
Private Image is available over the regular web (clearnet, via HTTPS) and through Tor as an onion
|
||||
@@ -180,7 +180,7 @@
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section id="compare" class="mt-16 scroll-mt-20">
|
||||
<section id="compare" class="mt-16 min-w-0 scroll-mt-16 sm:scroll-mt-20">
|
||||
<h2 class="text-lg font-medium text-foreground">How other image hosts compare</h2>
|
||||
<p class="mt-3 text-sm leading-relaxed text-muted-foreground sm:text-base sm:leading-relaxed">
|
||||
The table below compares Private Image with ImgBB, Imgur, and Catbox, three free image hosts commonly
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<main class="mx-auto flex max-w-lg flex-1 flex-col items-center justify-center gap-3 p-8 text-center">
|
||||
<main class="mx-auto flex w-full max-w-lg flex-1 flex-col items-center justify-center gap-3 px-4 py-6 text-center sm:p-8">
|
||||
<p v-if="state === 'invalid'" class="text-sm text-muted-foreground">
|
||||
This delete link is incomplete. Use the delete URL from your upload results.
|
||||
</p>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<main class="flex flex-1 items-center justify-center p-4">
|
||||
<img v-if="imageSrc" :src="imageSrc" class="max-h-[80vh] max-w-full object-contain" />
|
||||
<main class="flex w-full min-w-0 flex-1 flex-col items-center justify-center px-4 py-6 sm:px-6 sm:py-8">
|
||||
<img
|
||||
v-if="imageSrc"
|
||||
:src="imageSrc"
|
||||
class="max-h-[min(80vh,100dvh)] w-full object-contain"
|
||||
/>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<main class="mx-auto flex w-full max-w-3xl flex-1 flex-col gap-6 p-8">
|
||||
<main class="mx-auto flex w-full max-w-3xl flex-1 flex-col gap-4 p-4 sm:gap-6 sm:p-6 lg:p-8">
|
||||
<div class="flex flex-col gap-2">
|
||||
<UploadIntakeControls
|
||||
ref="intakeControlsRef"
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
<template>
|
||||
<main class="flex flex-1 items-center justify-center p-4">
|
||||
<p v-if="fetching" class="text-sm text-muted-foreground">Loading image...</p>
|
||||
<main class="flex w-full min-w-0 flex-1 flex-col items-center justify-center px-4 py-6 sm:px-6 sm:py-8">
|
||||
<p v-if="fetching" class="text-sm text-muted-foreground sm:text-base">Loading image...</p>
|
||||
|
||||
<form v-else-if="zkPayload" class="flex w-full max-w-sm flex-col gap-3" @submit.prevent="onUnlockSubmit">
|
||||
<form
|
||||
v-else-if="zkPayload"
|
||||
class="flex w-full max-w-sm flex-col gap-3"
|
||||
@submit.prevent="onUnlockSubmit"
|
||||
>
|
||||
<label class="flex flex-col gap-1.5 text-sm">
|
||||
<span>Password</span>
|
||||
<input
|
||||
v-model="password"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
class="rounded-md border border-input bg-background px-3 py-2 text-sm"
|
||||
class="rounded-md border border-input bg-background px-3 py-2.5 text-sm sm:py-2"
|
||||
:disabled="unlocking"
|
||||
/>
|
||||
</label>
|
||||
@@ -18,14 +22,18 @@
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
class="inline-flex w-full items-center justify-center rounded-md bg-primary px-4 py-2.5 text-sm font-medium text-primary-foreground transition-colors hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-60 sm:py-2"
|
||||
:disabled="unlocking || !password"
|
||||
>
|
||||
{{ unlocking ? 'Unlocking...' : 'View image' }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<img v-else-if="imageObjectUrl" :src="imageObjectUrl" class="max-h-[80vh] max-w-full object-contain" />
|
||||
<img
|
||||
v-else-if="imageObjectUrl"
|
||||
:src="imageObjectUrl"
|
||||
class="max-h-[min(80vh,100dvh)] w-full object-contain"
|
||||
/>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user