Improve narrow-viewport layout for upload, About, and shell overflow; keep modal scroll without extra dismiss or a11y markup changes.
136 lines
6.3 KiB
Vue
136 lines
6.3 KiB
Vue
<template>
|
|
<div class="flex flex-col gap-5">
|
|
<fieldset class="space-y-3">
|
|
<legend class="text-sm font-medium text-foreground">Share mode</legend>
|
|
|
|
<div class="space-y-3">
|
|
<label
|
|
class="flex cursor-pointer gap-3 rounded-md border border-border p-3 has-checked:border-primary has-checked:bg-muted/40"
|
|
>
|
|
<input v-model="settings.mode" class="mt-0.5" type="radio" name="upload-mode" value="zk" />
|
|
<span class="min-w-0 flex-1">
|
|
<span class="inline-flex flex-wrap items-center gap-x-2 gap-y-1">
|
|
<span class="text-sm font-medium">Zero knowledge</span>
|
|
<RouterLink
|
|
:to="{ name: ROUTE_NAMES.About, hash: '#zero-knowledge' }"
|
|
class="text-xs font-medium text-primary underline-offset-2 hover:underline"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
@click.stop
|
|
>
|
|
Learn more
|
|
</RouterLink>
|
|
</span>
|
|
<p class="mt-1 text-xs text-muted-foreground">
|
|
E2E encrypted, for direct sharing, can't be embedded.
|
|
</p>
|
|
</span>
|
|
</label>
|
|
|
|
<label
|
|
class="flex cursor-pointer gap-3 rounded-md border border-border p-3 has-checked:border-primary has-checked:bg-muted/40"
|
|
>
|
|
<input v-model="settings.mode" class="mt-0.5" type="radio" name="upload-mode" value="hotlink" />
|
|
<span class="min-w-0 flex-1">
|
|
<span class="inline-flex flex-wrap items-center gap-x-2 gap-y-1">
|
|
<span class="text-sm font-medium">Hotlink</span>
|
|
<RouterLink
|
|
:to="{ name: ROUTE_NAMES.About, hash: '#hotlink' }"
|
|
class="text-xs font-medium text-primary underline-offset-2 hover:underline"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
@click.stop
|
|
>
|
|
Learn more
|
|
</RouterLink>
|
|
</span>
|
|
<p class="mt-1 text-xs text-muted-foreground">
|
|
Still encrypted at rest, but support embedding, for forums, websites, etc.
|
|
</p>
|
|
</span>
|
|
</label>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<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="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 }}
|
|
</option>
|
|
</select>
|
|
</label>
|
|
|
|
<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="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 }}
|
|
</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
|
|
<div v-if="settings.mode === 'zk'" class="space-y-3 rounded-md border border-border p-3">
|
|
<label class="flex cursor-pointer items-center gap-2 text-sm">
|
|
<input v-model="settings.passwordEnabled" type="checkbox" class="rounded border-input" />
|
|
<span class="font-medium">Set password</span>
|
|
</label>
|
|
<p class="text-xs text-muted-foreground">Requires the link and this password to decrypt.</p>
|
|
|
|
<template v-if="settings.passwordEnabled">
|
|
<label class="flex flex-col gap-1.5 text-sm">
|
|
<span>Password</span>
|
|
<input
|
|
v-model="settings.password"
|
|
type="password"
|
|
autocomplete="new-password"
|
|
class="rounded-md border border-input bg-background px-3 py-2 text-base"
|
|
/>
|
|
</label>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue';
|
|
import { ROUTE_NAMES } from '@/consts/routeNames';
|
|
import { config } from '@/config';
|
|
import type { UploadBatchSettingsForm } from '@/types/upload/UploadBatchSettingsForm';
|
|
import type { UploadExpiryPreset } from '@/types/upload/UploadExpiryPreset';
|
|
import type { UploadMaxViewsPreset } from '@/types/upload/UploadMaxViewsPreset';
|
|
|
|
const settings = defineModel<UploadBatchSettingsForm>({ required: true });
|
|
|
|
const { maxViewsMax } = config.validation.upload;
|
|
|
|
const expiryOptions: { value: UploadExpiryPreset; label: string }[] = [
|
|
{ value: 'never', label: 'Never' },
|
|
{ value: '1h', label: '1 hour' },
|
|
{ value: '24h', label: '24 hours' },
|
|
{ value: '7d', label: '7 days' },
|
|
{ value: '30d', label: '30 days' }
|
|
];
|
|
|
|
const maxViewsOptions = computed(() => {
|
|
const options: { value: UploadMaxViewsPreset; label: string; numeric: number | null }[] = [
|
|
{ value: 'unlimited', label: 'Unlimited', numeric: null },
|
|
{ value: '1', label: '1- Burn after read', numeric: 1 },
|
|
{ value: '10', label: '10', numeric: 10 },
|
|
{ value: '100', label: '100', numeric: 100 },
|
|
{ value: '1000', label: '1000', numeric: 1000 },
|
|
{ value: '10000', label: '10000', numeric: 10000 }
|
|
];
|
|
|
|
return options.filter(option => option.numeric === null || option.numeric <= maxViewsMax);
|
|
});
|
|
</script>
|