mirror of
https://github.com/cupcakearmy/cryptgeon.git
synced 2026-04-02 09:55:23 +00:00
update to svelte 5
This commit is contained in:
@@ -1,10 +1,17 @@
|
||||
<script lang="ts">
|
||||
export let title: string
|
||||
import type { Snippet } from 'svelte'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
children?: Snippet
|
||||
}
|
||||
|
||||
let { title, children }: Props = $props()
|
||||
</script>
|
||||
|
||||
<p>
|
||||
<b>▶ {title}</b>
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</p>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -6,13 +6,23 @@
|
||||
import TextInput from '$lib/ui/TextInput.svelte'
|
||||
import type { Note } from 'cryptgeon/shared'
|
||||
|
||||
export let note: Note
|
||||
export let timeExpiration = false
|
||||
export let customPassword: string | null = null
|
||||
interface Props {
|
||||
note: Note
|
||||
timeExpiration?: boolean
|
||||
customPassword?: string | null
|
||||
}
|
||||
|
||||
let hasCustomPassword = false
|
||||
let {
|
||||
note = $bindable(),
|
||||
timeExpiration = $bindable(false),
|
||||
customPassword = $bindable(null),
|
||||
}: Props = $props()
|
||||
|
||||
$: if (!hasCustomPassword) customPassword = null
|
||||
let hasCustomPassword = $state(false)
|
||||
|
||||
$effect(() => {
|
||||
if (!hasCustomPassword) customPassword = null
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="flex col">
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
<button {...$$restProps} on:click><slot /></button>
|
||||
<script lang="ts">
|
||||
import type { HTMLButtonAttributes } from 'svelte/elements'
|
||||
|
||||
interface Props {
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let { children, ...rest }: HTMLButtonAttributes & Props = $props()
|
||||
</script>
|
||||
|
||||
<button {...rest}>{@render children?.()}</button>
|
||||
|
||||
<style>
|
||||
button {
|
||||
|
||||
@@ -5,11 +5,15 @@
|
||||
|
||||
import { getCSSVariable } from '$lib/utils'
|
||||
|
||||
export let value: string
|
||||
interface Props {
|
||||
value: string
|
||||
}
|
||||
|
||||
let canvas: HTMLCanvasElement
|
||||
let { value }: Props = $props()
|
||||
|
||||
$: {
|
||||
let canvas: HTMLCanvasElement | null = $state(null)
|
||||
|
||||
$effect(() => {
|
||||
new QR({
|
||||
value,
|
||||
level: 'Q',
|
||||
@@ -18,12 +22,12 @@
|
||||
foreground: getCSSVariable('--ui-text-0'),
|
||||
element: canvas,
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<small>{$t('common.qr_code')}</small>
|
||||
<div>
|
||||
<canvas bind:this={canvas} />
|
||||
<canvas bind:this={canvas}></canvas>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -5,8 +5,13 @@
|
||||
import MaxSize from '$lib/ui/MaxSize.svelte'
|
||||
import type { FileDTO } from 'cryptgeon/shared'
|
||||
|
||||
export let label: string = ''
|
||||
export let files: FileDTO[] = []
|
||||
interface Props {
|
||||
label?: string
|
||||
files?: FileDTO[]
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
let { label = '', files = $bindable([]), ...rest }: Props = $props()
|
||||
|
||||
async function fileToDTO(file: File): Promise<FileDTO> {
|
||||
return {
|
||||
@@ -35,7 +40,7 @@
|
||||
<small>
|
||||
{label}
|
||||
</small>
|
||||
<input {...$$restProps} type="file" on:change={onInput} multiple />
|
||||
<input {...rest} type="file" onchange={onInput} multiple />
|
||||
<div class="box">
|
||||
{#if files.length}
|
||||
<div>
|
||||
@@ -45,8 +50,8 @@
|
||||
{file.name}
|
||||
</div>
|
||||
{/each}
|
||||
<div class="spacer" />
|
||||
<Button on:click={clear}>{$t('file_upload.clear')}</Button>
|
||||
<div class="spacer"></div>
|
||||
<Button onclick={clear}>{$t('file_upload.clear')}</Button>
|
||||
</div>
|
||||
{:else}
|
||||
<div>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script lang="ts" context="module">
|
||||
<script lang="ts" module>
|
||||
import IconContrast from '$lib/icons/IconContrast.svelte'
|
||||
import IconCopy from '$lib/icons/IconCopy.svelte'
|
||||
import IconDice from '$lib/icons/IconDice.svelte'
|
||||
import IconEye from '$lib/icons/IconEye.svelte'
|
||||
import IconEyeOff from '$lib/icons/IconEyeOff.svelte'
|
||||
import type { HTMLButtonAttributes } from 'svelte/elements'
|
||||
|
||||
const map = {
|
||||
contrast: IconContrast,
|
||||
@@ -15,12 +16,17 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export let icon: keyof typeof map
|
||||
interface Props {
|
||||
icon: keyof typeof map
|
||||
}
|
||||
|
||||
let { icon, ...rest }: HTMLButtonAttributes & Props = $props()
|
||||
</script>
|
||||
|
||||
<button type="button" on:click {...$$restProps}>
|
||||
<button type="button" {...rest}>
|
||||
{#if map[icon]}
|
||||
<svelte:component this={map[icon]} />
|
||||
{@const SvelteComponent = map[icon]}
|
||||
<SvelteComponent />
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<script lang="ts"></script>
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
||||
|
Before Width: | Height: | Size: 784 B After Width: | Height: | Size: 813 B |
@@ -1,4 +1,4 @@
|
||||
<script lang="ts" context="module">
|
||||
<script lang="ts" module>
|
||||
export type NoteResult = {
|
||||
id: string
|
||||
password?: string
|
||||
@@ -12,9 +12,13 @@
|
||||
import TextInput from '$lib/ui/TextInput.svelte'
|
||||
import Canvas from './Canvas.svelte'
|
||||
|
||||
export let result: NoteResult
|
||||
interface Props {
|
||||
result: NoteResult
|
||||
}
|
||||
|
||||
let url = `${window.location.origin}/note/${result.id}`
|
||||
let { result }: Props = $props()
|
||||
|
||||
let url = $state(`${window.location.origin}/note/${result.id}`)
|
||||
if (result.password) url += `#${result.password}`
|
||||
|
||||
function reset() {
|
||||
@@ -41,7 +45,7 @@
|
||||
</p>
|
||||
{/if}
|
||||
<br />
|
||||
<Button on:click={reset}>{$t('home.new_note')}</Button>
|
||||
<Button onclick={reset}>{$t('home.new_note')}</Button>
|
||||
|
||||
<style>
|
||||
div {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script lang="ts" context="module">
|
||||
<script lang="ts" module>
|
||||
export type DecryptedNote = Omit<NotePublic, 'contents'> & { contents: any }
|
||||
|
||||
function saveAs(file: File) {
|
||||
@@ -22,20 +22,14 @@
|
||||
import { copy } from '$lib/utils'
|
||||
import type { FileDTO, NotePublic } from 'cryptgeon/shared'
|
||||
|
||||
export let note: DecryptedNote
|
||||
interface Props {
|
||||
note: DecryptedNote
|
||||
}
|
||||
|
||||
let { note }: Props = $props()
|
||||
|
||||
const RE_URL = /[A-Za-z]+:\/\/([A-Z a-z0-9\-._~:\/?#\[\]@!$&'()*+,;%=])+/g
|
||||
let files: FileDTO[] = []
|
||||
|
||||
$: if (note.meta.type === 'file') {
|
||||
files = note.contents
|
||||
}
|
||||
|
||||
$: download = () => {
|
||||
for (const file of files) {
|
||||
downloadFile(file)
|
||||
}
|
||||
}
|
||||
let files: FileDTO[] = $state([])
|
||||
|
||||
async function downloadFile(file: FileDTO) {
|
||||
const f = new File([file.contents], file.name, {
|
||||
@@ -44,7 +38,17 @@
|
||||
saveAs(f)
|
||||
}
|
||||
|
||||
$: links = typeof note.contents === 'string' ? note.contents.match(RE_URL) : []
|
||||
$effect(() => {
|
||||
if (note.meta.type === 'file') {
|
||||
files = note.contents
|
||||
}
|
||||
})
|
||||
let download = $derived(() => {
|
||||
for (const file of files) {
|
||||
downloadFile(file)
|
||||
}
|
||||
})
|
||||
let links = $derived(typeof note.contents === 'string' ? note.contents.match(RE_URL) : [])
|
||||
</script>
|
||||
|
||||
<p class="error-text">{@html $t('show.warning_will_not_see_again')}</p>
|
||||
@@ -53,7 +57,7 @@
|
||||
<div class="note">
|
||||
{note.contents}
|
||||
</div>
|
||||
<Button on:click={() => copy(note.contents)}>{$t('common.copy_clipboard')}</Button>
|
||||
<Button onclick={() => copy(note.contents)}>{$t('common.copy_clipboard')}</Button>
|
||||
|
||||
{#if links && links.length}
|
||||
<div class="links">
|
||||
@@ -70,13 +74,13 @@
|
||||
{:else}
|
||||
{#each files as file}
|
||||
<div class="note file">
|
||||
<button on:click={() => downloadFile(file)}>
|
||||
<button onclick={() => downloadFile(file)}>
|
||||
<b>↓ {file.name}</b>
|
||||
</button>
|
||||
<small> {file.type} - {prettyBytes(file.size)}</small>
|
||||
</div>
|
||||
{/each}
|
||||
<Button on:click={download}>{$t('show.download_all')}</Button>
|
||||
<Button onclick={download}>{$t('show.download_all')}</Button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
<script lang="ts">
|
||||
export let label: string = ''
|
||||
export let value: boolean
|
||||
export let color = true
|
||||
interface Props {
|
||||
label?: string
|
||||
value: boolean
|
||||
color?: boolean
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
let { label = '', value = $bindable(), color = true, ...rest }: Props = $props()
|
||||
</script>
|
||||
|
||||
<label {...$$restProps}>
|
||||
<label {...rest}>
|
||||
<small>{label}</small>
|
||||
<input type="checkbox" bind:checked={value} />
|
||||
<span class:color class="slider" />
|
||||
<span class:color class="slider"></span>
|
||||
</label>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
<script lang="ts">
|
||||
export let label: string = ''
|
||||
export let value: string
|
||||
interface Props {
|
||||
label?: string
|
||||
value: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
let { label = '', value = $bindable(), ...rest }: Props = $props()
|
||||
</script>
|
||||
|
||||
<label>
|
||||
<small>
|
||||
{label}
|
||||
</small>
|
||||
<textarea class="box" {...$$restProps} bind:value />
|
||||
<textarea class="box" {...rest} bind:value></textarea>
|
||||
</label>
|
||||
|
||||
@@ -2,24 +2,38 @@
|
||||
import Icon from '$lib/ui/Icon.svelte'
|
||||
import { copy as copyFN } from '$lib/utils'
|
||||
import { getRandomBytes, Hex } from 'occulto'
|
||||
import type { HTMLInputAttributes } from 'svelte/elements'
|
||||
|
||||
export let label: string = ''
|
||||
export let value: any
|
||||
export let validate: (value: any) => boolean | string = () => true
|
||||
export let copy: boolean = false
|
||||
export let random: boolean = false
|
||||
|
||||
const initialType = $$restProps.type
|
||||
const isPassword = initialType === 'password'
|
||||
let hidden = true
|
||||
|
||||
$: valid = validate(value)
|
||||
|
||||
$: if (isPassword) {
|
||||
value
|
||||
$$restProps.type = hidden ? initialType : 'text'
|
||||
interface Props {
|
||||
label?: string
|
||||
value: any
|
||||
validate?: (value: any) => boolean | string
|
||||
copy?: boolean
|
||||
random?: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
label = '',
|
||||
value = $bindable(),
|
||||
validate = () => true,
|
||||
copy = false,
|
||||
random = false,
|
||||
...rest
|
||||
}: HTMLInputAttributes & Props = $props()
|
||||
|
||||
const initialType = rest.type
|
||||
const isPassword = initialType === 'password'
|
||||
let hidden = $state(true)
|
||||
|
||||
let valid = $derived(validate(value))
|
||||
|
||||
$effect(() => {
|
||||
if (isPassword) {
|
||||
value
|
||||
rest.type = hidden ? initialType : 'text'
|
||||
}
|
||||
})
|
||||
|
||||
function toggle() {
|
||||
hidden = !hidden
|
||||
}
|
||||
@@ -30,31 +44,31 @@
|
||||
</script>
|
||||
|
||||
<label>
|
||||
<small class:disabled={$$restProps.disabled}>
|
||||
<small class:disabled={rest.disabled}>
|
||||
{label}
|
||||
{#if valid !== true}
|
||||
<span class="error-text">{valid}</span>
|
||||
{/if}
|
||||
</small>
|
||||
<input bind:value {...$$restProps} class:valid={valid === true} />
|
||||
<input bind:value {...rest} class:valid={valid === true} />
|
||||
<div class="icons">
|
||||
{#if isPassword}
|
||||
<Icon
|
||||
disabled={$$restProps.disabled}
|
||||
disabled={rest.disabled}
|
||||
class="icon"
|
||||
icon={hidden ? 'eye' : 'eye-off'}
|
||||
on:click={toggle}
|
||||
onclick={toggle}
|
||||
/>
|
||||
{/if}
|
||||
{#if random}
|
||||
<Icon disabled={$$restProps.disabled} class="icon" icon="dice" on:click={randomFN} />
|
||||
<Icon disabled={rest.disabled} class="icon" icon="dice" onclick={randomFN} />
|
||||
{/if}
|
||||
{#if copy}
|
||||
<Icon
|
||||
disabled={$$restProps.disabled}
|
||||
disabled={rest.disabled}
|
||||
class="icon"
|
||||
icon="copy"
|
||||
on:click={() => copyFN(value.toString())}
|
||||
onclick={() => copyFN(value.toString())}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
<script lang="ts" context="module">
|
||||
<script lang="ts" module>
|
||||
import { writable } from 'svelte/store'
|
||||
|
||||
enum Theme {
|
||||
Dark = 'dark',
|
||||
Light = 'light',
|
||||
Auto = 'auto',
|
||||
}
|
||||
const themes = ['dark', 'light', 'auto'] as const
|
||||
type Theme = (typeof themes)[number]
|
||||
|
||||
const NextTheme = {
|
||||
[Theme.Auto]: Theme.Light,
|
||||
[Theme.Light]: Theme.Dark,
|
||||
[Theme.Dark]: Theme.Auto,
|
||||
const NextTheme: Record<Theme, Theme> = {
|
||||
auto: 'light',
|
||||
light: 'dark',
|
||||
dark: 'auto',
|
||||
}
|
||||
|
||||
function init(): Theme {
|
||||
if (typeof window !== 'undefined') {
|
||||
const saved = window.localStorage.getItem('theme') as Theme
|
||||
if (Object.values(Theme).includes(saved)) return saved
|
||||
if (themes.includes(saved)) return saved
|
||||
}
|
||||
return Theme.Auto
|
||||
return 'auto'
|
||||
}
|
||||
|
||||
export const theme = writable<Theme>(init())
|
||||
@@ -40,7 +37,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<button on:click={change}>
|
||||
<button onclick={change}>
|
||||
<Icon class="icon" icon="contrast" />
|
||||
{$theme}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user