mirror of
https://codeberg.org/Freedium-cfd/web.git
synced 2026-03-11 09:04:37 +00:00
feat(package): update dependencies and enhance UI components
This commit is contained in:
parent
f8df59680f
commit
1a7954d54e
15 changed files with 500 additions and 151 deletions
Binary file not shown.
|
|
@ -12,35 +12,37 @@
|
|||
"format": "prettier --write ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"@sveltejs/adapter-auto": "^3.3.1",
|
||||
"@sveltejs/kit": "^2.7.4",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.1.2",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk-sv": "^0.0.18",
|
||||
"lucide-svelte": "^0.453.0",
|
||||
"mode-watcher": "^0.4.1",
|
||||
"postcss": "^8.4.47",
|
||||
"prettier": "^3.1.1",
|
||||
"prettier-plugin-svelte": "^3.1.2",
|
||||
"svelte": "^4.2.7",
|
||||
"svelte-check": "^4.0.0",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-svelte": "^3.2.7",
|
||||
"svelte": "^4.2.19",
|
||||
"svelte-check": "^4.0.5",
|
||||
"svelte-sonner": "^0.3.28",
|
||||
"tailwind-merge": "^2.5.4",
|
||||
"tailwind-variants": "^0.2.1",
|
||||
"tailwindcss": "^3.4.13",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^5.0.3"
|
||||
"tailwindcss": "^3.4.14",
|
||||
"typescript": "^5.6.3",
|
||||
"vaul-svelte": "^0.3.2",
|
||||
"vite": "^5.4.10"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@iconify/svelte": "^4.0.2",
|
||||
"bits-ui": "^0.21.16",
|
||||
"copy-to-clipboard": "^3.3.3",
|
||||
"es-toolkit": "^1.25.2",
|
||||
"es-toolkit": "^1.26.1",
|
||||
"medium-zoom": "^1.1.0",
|
||||
"svelte-bricks": "^0.2.1",
|
||||
"svelte-lazy": "^1.2.9",
|
||||
"svelte-lazy": "1.2.9",
|
||||
"svelte-legos": "^0.2.5",
|
||||
"svelte-markdown": "^0.4.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0, 0%, 97%;
|
||||
|
|
|
|||
24
new-web/src/lib/components/ui/drawer/drawer-content.svelte
Normal file
24
new-web/src/lib/components/ui/drawer/drawer-content.svelte
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<script lang="ts">
|
||||
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||
import DrawerOverlay from "./drawer-overlay.svelte";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = DrawerPrimitive.ContentProps;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DrawerPrimitive.Portal>
|
||||
<DrawerOverlay />
|
||||
<DrawerPrimitive.Content
|
||||
class={cn(
|
||||
"bg-background fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<div class="bg-muted mx-auto mt-4 h-2 w-[100px] rounded-full"></div>
|
||||
<slot />
|
||||
</DrawerPrimitive.Content>
|
||||
</DrawerPrimitive.Portal>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<script lang="ts">
|
||||
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = DrawerPrimitive.DescriptionProps;
|
||||
|
||||
export let el: $$Props["el"] = undefined;
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DrawerPrimitive.Description
|
||||
bind:el
|
||||
class={cn("text-muted-foreground text-sm", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</DrawerPrimitive.Description>
|
||||
16
new-web/src/lib/components/ui/drawer/drawer-footer.svelte
Normal file
16
new-web/src/lib/components/ui/drawer/drawer-footer.svelte
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<script lang="ts">
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLDivElement> & {
|
||||
el?: HTMLDivElement;
|
||||
};
|
||||
|
||||
export let el: $$Props["el"] = undefined;
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div bind:this={el} class={cn("mt-auto flex flex-col gap-2 p-4", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</div>
|
||||
19
new-web/src/lib/components/ui/drawer/drawer-header.svelte
Normal file
19
new-web/src/lib/components/ui/drawer/drawer-header.svelte
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<script lang="ts">
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLDivElement> & {
|
||||
el?: HTMLDivElement;
|
||||
};
|
||||
export let el: $$Props["el"] = undefined;
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div
|
||||
bind:this={el}
|
||||
class={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
12
new-web/src/lib/components/ui/drawer/drawer-nested.svelte
Normal file
12
new-web/src/lib/components/ui/drawer/drawer-nested.svelte
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<script lang="ts">
|
||||
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||
|
||||
type $$Props = DrawerPrimitive.Props;
|
||||
export let shouldScaleBackground: $$Props["shouldScaleBackground"] = true;
|
||||
export let open: $$Props["open"] = false;
|
||||
export let activeSnapPoint: $$Props["activeSnapPoint"] = undefined;
|
||||
</script>
|
||||
|
||||
<DrawerPrimitive.NestedRoot {shouldScaleBackground} bind:open bind:activeSnapPoint {...$$restProps}>
|
||||
<slot />
|
||||
</DrawerPrimitive.NestedRoot>
|
||||
18
new-web/src/lib/components/ui/drawer/drawer-overlay.svelte
Normal file
18
new-web/src/lib/components/ui/drawer/drawer-overlay.svelte
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<script lang="ts">
|
||||
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = DrawerPrimitive.OverlayProps;
|
||||
|
||||
export let el: $$Props["el"] = undefined;
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DrawerPrimitive.Overlay
|
||||
bind:el
|
||||
class={cn("fixed inset-0 z-50 bg-black/80", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</DrawerPrimitive.Overlay>
|
||||
18
new-web/src/lib/components/ui/drawer/drawer-title.svelte
Normal file
18
new-web/src/lib/components/ui/drawer/drawer-title.svelte
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<script lang="ts">
|
||||
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = DrawerPrimitive.TitleProps;
|
||||
|
||||
export let el: $$Props["el"] = undefined;
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DrawerPrimitive.Title
|
||||
bind:el
|
||||
class={cn("text-lg font-semibold leading-none tracking-tight", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</DrawerPrimitive.Title>
|
||||
12
new-web/src/lib/components/ui/drawer/drawer.svelte
Normal file
12
new-web/src/lib/components/ui/drawer/drawer.svelte
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<script lang="ts">
|
||||
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||
|
||||
type $$Props = DrawerPrimitive.Props;
|
||||
export let shouldScaleBackground: $$Props["shouldScaleBackground"] = true;
|
||||
export let open: $$Props["open"] = false;
|
||||
export let activeSnapPoint: $$Props["activeSnapPoint"] = undefined;
|
||||
</script>
|
||||
|
||||
<DrawerPrimitive.Root {shouldScaleBackground} bind:open bind:activeSnapPoint {...$$restProps}>
|
||||
<slot />
|
||||
</DrawerPrimitive.Root>
|
||||
41
new-web/src/lib/components/ui/drawer/index.ts
Normal file
41
new-web/src/lib/components/ui/drawer/index.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import { Drawer as DrawerPrimitive } from "vaul-svelte";
|
||||
|
||||
import Root from "./drawer.svelte";
|
||||
import Content from "./drawer-content.svelte";
|
||||
import Description from "./drawer-description.svelte";
|
||||
import Overlay from "./drawer-overlay.svelte";
|
||||
import Footer from "./drawer-footer.svelte";
|
||||
import Header from "./drawer-header.svelte";
|
||||
import Title from "./drawer-title.svelte";
|
||||
import NestedRoot from "./drawer-nested.svelte";
|
||||
|
||||
const Trigger = DrawerPrimitive.Trigger;
|
||||
const Portal = DrawerPrimitive.Portal;
|
||||
const Close = DrawerPrimitive.Close;
|
||||
|
||||
export {
|
||||
Root,
|
||||
NestedRoot,
|
||||
Content,
|
||||
Description,
|
||||
Overlay,
|
||||
Footer,
|
||||
Header,
|
||||
Title,
|
||||
Trigger,
|
||||
Portal,
|
||||
Close,
|
||||
|
||||
//
|
||||
Root as Drawer,
|
||||
NestedRoot as DrawerNestedRoot,
|
||||
Content as DrawerContent,
|
||||
Description as DrawerDescription,
|
||||
Overlay as DrawerOverlay,
|
||||
Footer as DrawerFooter,
|
||||
Header as DrawerHeader,
|
||||
Title as DrawerTitle,
|
||||
Trigger as DrawerTrigger,
|
||||
Portal as DrawerPortal,
|
||||
Close as DrawerClose,
|
||||
};
|
||||
|
|
@ -3,91 +3,175 @@
|
|||
import { Button, buttonVariants } from '$lib/components/ui/button/index.js';
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu/index.js';
|
||||
import * as Dialog from '$lib/components/ui/dialog';
|
||||
import * as Drawer from '$lib/components/ui/drawer';
|
||||
import { mediaQuery } from 'svelte-legos';
|
||||
import CodeBlock from './CodeBlock.svelte';
|
||||
import copy from 'copy-to-clipboard';
|
||||
import { toast } from 'svelte-sonner';
|
||||
|
||||
let open = false;
|
||||
const isDesktop = mediaQuery('(min-width: 768px)');
|
||||
|
||||
function handleCopy(text: string) {
|
||||
copy(text);
|
||||
toast.success('Copied to clipboard');
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger class="w-full">
|
||||
<DropdownMenu.Item on:click={($event) => $event.preventDefault()}>
|
||||
<Icon icon="mdi:bookmark" class="w-4 h-4 mr-2" />
|
||||
<span>Bookmark</span>
|
||||
</DropdownMenu.Item>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Content
|
||||
class="w-full max-w-[94%] sm:max-w-[490px] md:w-full bg-white dark:bg-zinc-900 flex flex-col"
|
||||
>
|
||||
<Dialog.Header>
|
||||
<Dialog.Title class="text-lg font-semibold tracking-tight"
|
||||
>Add Bookmark for Medium Bypass</Dialog.Title
|
||||
>
|
||||
</Dialog.Header>
|
||||
<div class="flex-1">
|
||||
<Dialog.Description class="space-y-4 text-foreground-alt">
|
||||
<p class="text-sm italic">
|
||||
Credit: blazeknifecatcher on <a
|
||||
href="https://www.reddit.com/r/paywall/comments/15jsr6z/bypass_mediumcom_paywall/"
|
||||
class="text-blue-500 hover:underline"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">Reddit</a
|
||||
>
|
||||
</p>
|
||||
|
||||
<div class="p-4 bg-gray-100 rounded-lg dark:bg-zinc-800">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h3 class="mt-2 font-semibold">Option 1: Redirect in Current Tab</h3>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="ml-2"
|
||||
on:click={() =>
|
||||
handleCopy(
|
||||
`javascript:window.location="https://freedium.cfd/"+encodeURIComponent(window.location)"`
|
||||
)}
|
||||
{#if $isDesktop}
|
||||
<Dialog.Root bind:open>
|
||||
<Dialog.Trigger class="w-full">
|
||||
<DropdownMenu.Item on:click={($event) => $event.preventDefault()}>
|
||||
<Icon icon="mdi:bookmark" class="w-4 h-4 mr-2" />
|
||||
<span>Bookmark</span>
|
||||
</DropdownMenu.Item>
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Content
|
||||
class="w-full max-w-[94%] sm:max-w-[490px] md:w-full bg-white dark:bg-zinc-900 flex flex-col"
|
||||
>
|
||||
<Dialog.Header>
|
||||
<Dialog.Title class="text-lg font-semibold tracking-tight"
|
||||
>Add Bookmark for Medium Bypass</Dialog.Title
|
||||
>
|
||||
</Dialog.Header>
|
||||
<div class="flex-1">
|
||||
<Dialog.Description class="space-y-4 text-foreground-alt">
|
||||
<p class="text-sm italic">
|
||||
Credit: blazeknifecatcher on <a
|
||||
href="https://www.reddit.com/r/paywall/comments/15jsr6z/bypass_mediumcom_paywall/"
|
||||
class="text-blue-500 hover:underline"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">Reddit</a
|
||||
>
|
||||
<Icon icon="mdi:content-copy" class="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<p class="mb-2">Create a new bookmark with the following code as the URL:</p>
|
||||
</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`javascript:window.location="https://freedium.cfd/"+encodeURIComponent(window.location)"`}
|
||||
/>
|
||||
</div>
|
||||
<div class="p-4 bg-gray-100 rounded-lg dark:bg-zinc-800">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h3 class="mt-2 font-semibold">Option 1: Redirect in Current Tab</h3>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="ml-2"
|
||||
on:click={() =>
|
||||
handleCopy(
|
||||
`javascript:window.location="https://freedium.cfd/"+encodeURIComponent(window.location)"`
|
||||
)}
|
||||
>
|
||||
<Icon icon="mdi:content-copy" class="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<p class="mb-2">Create a new bookmark with the following code as the URL:</p>
|
||||
|
||||
<div class="p-4 bg-gray-100 rounded-lg dark:bg-zinc-800">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h3 class="mt-2 font-semibold">Option 2: Open in New Tab</h3>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="ml-2"
|
||||
on:click={() =>
|
||||
handleCopy(
|
||||
`javascript:(function(){window.open("https://freedium.cfd/"+encodeURIComponent(window.location))})();`
|
||||
)}
|
||||
>
|
||||
<Icon icon="mdi:content-copy" class="w-4 h-4" />
|
||||
</Button>
|
||||
<CodeBlock
|
||||
code={`javascript:window.location="https://freedium.cfd/"+encodeURIComponent(window.location)"`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<p class="mb-2">For opening in a new tab, use this code instead:</p>
|
||||
<CodeBlock
|
||||
code={`javascript:(function(){window.open("https://freedium.cfd/"+encodeURIComponent(window.location))})();`}
|
||||
/>
|
||||
</div>
|
||||
<div class="p-4 bg-gray-100 rounded-lg dark:bg-zinc-800">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h3 class="mt-2 font-semibold">Option 2: Open in New Tab</h3>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="ml-2"
|
||||
on:click={() =>
|
||||
handleCopy(
|
||||
`javascript:(function(){window.open("https://freedium.cfd/"+encodeURIComponent(window.location))})();`
|
||||
)}
|
||||
>
|
||||
<Icon icon="mdi:content-copy" class="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<p>Click the bookmark on any Medium page to bypass the paywall using Freedium.</p>
|
||||
</Dialog.Description>
|
||||
</div>
|
||||
<Dialog.Footer class="flex justify-end p-4">
|
||||
<Dialog.Close class={buttonVariants({ variant: 'outline' })}>Close</Dialog.Close>
|
||||
</Dialog.Footer>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
<p class="mb-2">For opening in a new tab, use this code instead:</p>
|
||||
<CodeBlock
|
||||
code={`javascript:(function(){window.open("https://freedium.cfd/"+encodeURIComponent(window.location))})();`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<p>Click the bookmark on any Medium page to bypass the paywall using Freedium.</p>
|
||||
</Dialog.Description>
|
||||
</div>
|
||||
<Dialog.Footer class="flex justify-end p-4">
|
||||
<Dialog.Close class={buttonVariants({ variant: 'outline' })}>Close</Dialog.Close>
|
||||
</Dialog.Footer>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
{:else}
|
||||
<Drawer.Root bind:open>
|
||||
<Drawer.Trigger class="w-full">
|
||||
<DropdownMenu.Item on:click={($event) => $event.preventDefault()}>
|
||||
<Icon icon="mdi:bookmark" class="w-4 h-4 mr-2" />
|
||||
<span>Bookmark</span>
|
||||
</DropdownMenu.Item>
|
||||
</Drawer.Trigger>
|
||||
<Drawer.Content class="bg-white dark:bg-zinc-900">
|
||||
<Drawer.Header>
|
||||
<Drawer.Title class="text-lg font-semibold tracking-tight">
|
||||
Add Bookmark for Medium Bypass
|
||||
</Drawer.Title>
|
||||
</Drawer.Header>
|
||||
<div class="flex-1 px-4">
|
||||
<div class="space-y-4 text-foreground-alt">
|
||||
<p class="text-sm italic">
|
||||
Credit: blazeknifecatcher on <a
|
||||
href="https://www.reddit.com/r/paywall/comments/15jsr6z/bypass_mediumcom_paywall/"
|
||||
class="text-blue-500 hover:underline"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">Reddit</a
|
||||
>
|
||||
</p>
|
||||
|
||||
<div class="p-4 bg-gray-100 rounded-lg dark:bg-zinc-800">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h3 class="mt-2 font-semibold">Option 1: Redirect in Current Tab</h3>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="ml-2"
|
||||
on:click={() =>
|
||||
handleCopy(
|
||||
`javascript:window.location="https://freedium.cfd/"+encodeURIComponent(window.location)"`
|
||||
)}
|
||||
>
|
||||
<Icon icon="mdi:content-copy" class="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<p class="mb-2">Create a new bookmark with the following code as the URL:</p>
|
||||
|
||||
<CodeBlock
|
||||
code={`javascript:window.location="https://freedium.cfd/"+encodeURIComponent(window.location)"`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="p-4 bg-gray-100 rounded-lg dark:bg-zinc-800">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h3 class="mt-2 font-semibold">Option 2: Open in New Tab</h3>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class="ml-2"
|
||||
on:click={() =>
|
||||
handleCopy(
|
||||
`javascript:(function(){window.open("https://freedium.cfd/"+encodeURIComponent(window.location))})();`
|
||||
)}
|
||||
>
|
||||
<Icon icon="mdi:content-copy" class="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<p class="mb-2">For opening in a new tab, use this code instead:</p>
|
||||
<CodeBlock
|
||||
code={`javascript:(function(){window.open("https://freedium.cfd/"+encodeURIComponent(window.location))})();`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<p>Click the bookmark on any Medium page to bypass the paywall using Freedium.</p>
|
||||
</div>
|
||||
</div>
|
||||
<Drawer.Footer class="flex justify-end p-4">
|
||||
<Drawer.Close class={buttonVariants({ variant: 'outline' })}>Close</Drawer.Close>
|
||||
</Drawer.Footer>
|
||||
</Drawer.Content>
|
||||
</Drawer.Root>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -29,5 +29,11 @@
|
|||
bind:this={progress}
|
||||
id="progress"
|
||||
class="top-0 z-20 h-1"
|
||||
style="background:linear-gradient(to right, hsl(var(--primary)) var(--scroll), transparent 0)"
|
||||
style="background:linear-gradient(to right, hsl(var(--primary)) var(--scroll), transparent 0); width: var(--scroll, 0%);"
|
||||
/>
|
||||
|
||||
<style>
|
||||
#progress {
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
<script lang="ts">
|
||||
import Icon from '@iconify/svelte';
|
||||
import { Label, Separator } from 'bits-ui';
|
||||
import { mediaQuery } from 'svelte-legos';
|
||||
import { Textarea } from '$lib/components/ui/textarea/index.js';
|
||||
import { Button, buttonVariants } from '$lib/components/ui/button/index.js';
|
||||
import * as Dialog from '$lib/components/ui/dialog';
|
||||
import * as Drawer from '$lib/components/ui/drawer';
|
||||
import * as RadioGroup from '$lib/components/ui/radio-group/index.js';
|
||||
import { toast } from 'svelte-sonner';
|
||||
|
||||
let open = false;
|
||||
const isDesktop = mediaQuery('(min-width: 768px)');
|
||||
let problemDescription = '';
|
||||
let problemType = 'ui_problem';
|
||||
|
||||
|
|
@ -15,76 +19,147 @@
|
|||
toast.success(`${problemType} submitted`);
|
||||
problemDescription = '';
|
||||
problemType = 'ui_problem';
|
||||
open = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger class={buttonVariants({ variant: 'default' })}>
|
||||
<div class="flex items-center space-x-2 text-white">
|
||||
<Icon icon="heroicons:exclamation-triangle-solid" class="size-5" />
|
||||
<span class="text-sm font-medium">Report a problem</span>
|
||||
</div>
|
||||
</Dialog.Trigger>
|
||||
<form on:submit={handleSubmit}>
|
||||
<Dialog.Content
|
||||
class="w-full max-w-[94%] sm:max-w-[490px] md:w-full bg-white dark:bg-zinc-900 flex flex-col"
|
||||
>
|
||||
<Dialog.Header>
|
||||
<Dialog.Title class="text-lg font-semibold tracking-tight">Report a Problem</Dialog.Title>
|
||||
</Dialog.Header>
|
||||
<div class="flex-1">
|
||||
<Dialog.Description class="text-foreground-alt">
|
||||
<p>
|
||||
{#if $isDesktop}
|
||||
<Dialog.Root bind:open>
|
||||
<Dialog.Trigger class={buttonVariants({ variant: 'default' })}>
|
||||
<div class="flex items-center space-x-2 text-white">
|
||||
<Icon icon="heroicons:exclamation-triangle-solid" class="size-5" />
|
||||
<span class="text-sm font-medium">Report a problem</span>
|
||||
</div>
|
||||
</Dialog.Trigger>
|
||||
<form on:submit|preventDefault={handleSubmit}>
|
||||
<Dialog.Content class="w-full max-w-[650px] bg-white dark:bg-zinc-900 flex flex-col">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title class="text-lg font-semibold tracking-tight">Report a Problem</Dialog.Title>
|
||||
</Dialog.Header>
|
||||
<div class="flex-1">
|
||||
<Dialog.Description class="text-foreground-alt">
|
||||
<p>
|
||||
Please describe the problem you're experiencing. We'll look into it as soon as
|
||||
possible.
|
||||
</p>
|
||||
</Dialog.Description>
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 pt-7">
|
||||
<div class="flex flex-col items-start gap-2">
|
||||
<Label.Root class="text-sm font-medium">Problem Type</Label.Root>
|
||||
<RadioGroup.Root bind:value={problemType} class="space-y-2">
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="ui_problem" id="ui-problem" />
|
||||
<Label.Root for="ui-problem">UI problem</Label.Root>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="article_not_full" id="article-not-full" />
|
||||
<Label.Root for="article-not-full">Article is not full</Label.Root>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="suggestion" id="suggestion" />
|
||||
<Label.Root for="suggestion">Suggestion</Label.Root>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="vulnerability" id="vulnerability" />
|
||||
<Label.Root for="vulnerability">Vulnerability (XSS, etc.)</Label.Root>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="other" id="other" />
|
||||
<Label.Root for="other">Other</Label.Root>
|
||||
</div>
|
||||
</RadioGroup.Root>
|
||||
</div>
|
||||
<div class="flex flex-col items-start gap-1">
|
||||
<Label.Root for="problemDescription" class="text-sm font-medium"
|
||||
>Problem Description</Label.Root
|
||||
>
|
||||
<Textarea
|
||||
id="problemDescription"
|
||||
bind:value={problemDescription}
|
||||
placeholder="Describe the problem you're experiencing..."
|
||||
rows={12}
|
||||
/>
|
||||
<p class="mt-2 text-sm text-foreground-alt">
|
||||
The current opened page will be automatically attached to your report.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="self-end p-4">
|
||||
<Dialog.Footer>
|
||||
<Dialog.Close class={buttonVariants({ variant: 'outline' })}>Cancel</Dialog.Close>
|
||||
<Button type="submit">Submit</Button>
|
||||
</Dialog.Footer>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</form>
|
||||
</Dialog.Root>
|
||||
{:else}
|
||||
<Drawer.Root bind:open>
|
||||
<Drawer.Trigger class={buttonVariants({ variant: 'default' })}>
|
||||
<div class="flex items-center space-x-2 text-white">
|
||||
<Icon icon="heroicons:exclamation-triangle-solid" class="size-5" />
|
||||
<span class="text-sm font-medium">Report a problem</span>
|
||||
</div>
|
||||
</Drawer.Trigger>
|
||||
<form on:submit|preventDefault={handleSubmit}>
|
||||
<Drawer.Content>
|
||||
<Drawer.Header class="text-left">
|
||||
<Drawer.Title class="text-lg font-semibold tracking-tight">Report a Problem</Drawer.Title>
|
||||
<Drawer.Description class="text-foreground-alt">
|
||||
Please describe the problem you're experiencing. We'll look into it as soon as possible.
|
||||
</p>
|
||||
</Dialog.Description>
|
||||
<div class="flex flex-col items-start gap-2 pb-6 pt-7">
|
||||
<Label.Root class="text-sm font-medium">Problem Type</Label.Root>
|
||||
<RadioGroup.Root bind:value={problemType} class="space-y-2">
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="ui_problem" id="ui-problem" />
|
||||
<Label.Root for="ui-problem">UI problem</Label.Root>
|
||||
</Drawer.Description>
|
||||
</Drawer.Header>
|
||||
<div class="px-4">
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 pt-7">
|
||||
<div class="flex flex-col items-start gap-2">
|
||||
<Label.Root class="text-sm font-medium">Problem Type</Label.Root>
|
||||
<RadioGroup.Root bind:value={problemType} class="space-y-2">
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="ui_problem" id="ui-problem-mobile" />
|
||||
<Label.Root for="ui-problem-mobile">UI problem</Label.Root>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="article_not_full" id="article-not-full-mobile" />
|
||||
<Label.Root for="article-not-full-mobile">Article is not full</Label.Root>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="suggestion" id="suggestion-mobile" />
|
||||
<Label.Root for="suggestion-mobile">Suggestion</Label.Root>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="vulnerability" id="vulnerability-mobile" />
|
||||
<Label.Root for="vulnerability-mobile">Vulnerability (XSS, etc.)</Label.Root>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="other" id="other-mobile" />
|
||||
<Label.Root for="other-mobile">Other</Label.Root>
|
||||
</div>
|
||||
</RadioGroup.Root>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="article_not_full" id="article-not-full" />
|
||||
<Label.Root for="article-not-full">Article is not full</Label.Root>
|
||||
<div class="flex flex-col items-start gap-1">
|
||||
<Label.Root for="problemDescription-mobile" class="text-sm font-medium"
|
||||
>Problem Description</Label.Root
|
||||
>
|
||||
<Textarea
|
||||
id="problemDescription-mobile"
|
||||
bind:value={problemDescription}
|
||||
placeholder="Describe the problem you're experiencing..."
|
||||
rows={12}
|
||||
/>
|
||||
<p class="mt-2 text-sm text-foreground-alt">
|
||||
The current opened page will be automatically attached to your report.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="suggestion" id="suggestion" />
|
||||
<Label.Root for="suggestion">Suggestion</Label.Root>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="vulnerability" id="vulnerability" />
|
||||
<Label.Root for="vulnerability">Vulnerability (XSS, etc.)</Label.Root>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="other" id="other" />
|
||||
<Label.Root for="other">Other</Label.Root>
|
||||
</div>
|
||||
</RadioGroup.Root>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-start gap-1 pb-6">
|
||||
<Label.Root for="problemDescription" class="text-sm font-medium">
|
||||
Problem Description
|
||||
</Label.Root>
|
||||
<Textarea
|
||||
id="problemDescription"
|
||||
bind:value={problemDescription}
|
||||
placeholder="Describe the problem you're experiencing..."
|
||||
rows={12}
|
||||
></Textarea>
|
||||
<p class="mt-2 text-sm text-foreground-alt">
|
||||
The current opened page will be automatically attached to your report.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="self-end p-4">
|
||||
<Dialog.Footer>
|
||||
<Dialog.Close class={buttonVariants({ variant: 'outline' })}>Cancel</Dialog.Close>
|
||||
<Button type="submit" on:click={handleSubmit}>Submit</Button>
|
||||
</Dialog.Footer>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</form>
|
||||
</Dialog.Root>
|
||||
<Drawer.Footer class="p-4">
|
||||
<div class="flex justify-end gap-2">
|
||||
<Drawer.Close class={buttonVariants({ variant: 'outline' })}>Cancel</Drawer.Close>
|
||||
<Button type="submit">Submit</Button>
|
||||
</div>
|
||||
</Drawer.Footer>
|
||||
</Drawer.Content>
|
||||
</form>
|
||||
</Drawer.Root>
|
||||
{/if}
|
||||
|
|
|
|||
Loading…
Reference in a new issue