feat: Privacy popup
This commit is contained in:
+2
-2
@@ -38,7 +38,7 @@
|
||||
"@typescript-eslint/parser": "6.21.0",
|
||||
"@vitest/ui": "^2.1.4",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"bits-ui": "^1.3.6",
|
||||
"bits-ui": "^1.3.12",
|
||||
"c8": "7.14.0",
|
||||
"chai": "^4.3.7",
|
||||
"clsx": "^2.1.1",
|
||||
@@ -59,7 +59,7 @@
|
||||
"husky": "^8.0.3",
|
||||
"jsdom": "^25.0.1",
|
||||
"lint-staged": "^15.2.0",
|
||||
"lucide-svelte": "^0.477.0",
|
||||
"lucide-svelte": "^0.479.0",
|
||||
"node-html-parser": "^6.1.5",
|
||||
"paneforge": "^1.0.0-next.4",
|
||||
"postcss": "^8.4.33",
|
||||
|
||||
@@ -175,10 +175,6 @@
|
||||
<!-- <span class="text-sm">v{version}</span> -->
|
||||
<div
|
||||
class="h-full items-center justify-between gap-2 overflow-hidden pt-4 text-base lg:flex lg:pt-0">
|
||||
<!-- <li>
|
||||
<Privacy />
|
||||
</li> -->
|
||||
|
||||
<!-- <DropdownNavMenu label="Documentation" links={documentationLinks} /> -->
|
||||
<Button onclick={toggleMode} variant="outline" size="icon" title="Toggle theme">
|
||||
<SunIcon
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
<script>
|
||||
import ShieldHalvedIcon from '~icons/fa6-solid/shield-halved';
|
||||
import * as Dialog from '$/components/ui/dialog';
|
||||
import ShieldIcon from '~icons/material-symbols/shield-lock-outline-rounded';
|
||||
</script>
|
||||
|
||||
<label for="privacyModal" class="btn btn-ghost flex gap-2">
|
||||
<ShieldHalvedIcon /> Security
|
||||
</label>
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>
|
||||
<ShieldIcon />
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Content>
|
||||
<Dialog.Header>
|
||||
<Dialog.Title class="flex items-center gap-2 text-xl">
|
||||
<ShieldIcon class="size-8 text-green-700" />Data security</Dialog.Title>
|
||||
<Dialog.Description></Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<input type="checkbox" id="privacyModal" class="modal-toggle" />
|
||||
<div class="modal" role="dialog">
|
||||
<div class="modal-box text-base-content flex flex-col gap-4">
|
||||
<h1 class="text-3xl font-bold">Data security</h1>
|
||||
<p>
|
||||
<span class="text-xl font-extrabold">
|
||||
The content of the diagrams you create never leaves your browser.
|
||||
</span>
|
||||
It's stored in the URL, and the browser's local storage only.
|
||||
<p class="text-xl font-semibold">
|
||||
The content of the diagrams you create never leaves your browser.
|
||||
</p>
|
||||
<p>It's stored in the URL, and the browser's local storage only.</p>
|
||||
<p>
|
||||
Mermaid live editor is a fully client side application, that will also work as an offline <a
|
||||
href="https://web.dev/explore/progressive-web-apps"
|
||||
class="link"
|
||||
class="underline"
|
||||
target="_blank">
|
||||
PWA.
|
||||
Progressive Web App.
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
@@ -29,7 +31,7 @@
|
||||
Plausible Analytics. We only collect data related to actions performed, like the type of
|
||||
diagram rendered, number of times a feature was used, etc. <br /> All the data we collect is
|
||||
anonymized and
|
||||
<a href="https://p.mermaid.live/mermaid.live" class="link" target="_blank">
|
||||
<a href="https://p.mermaid.live/mermaid.live" class="underline" target="_blank">
|
||||
available publicly.
|
||||
</a>
|
||||
</p>
|
||||
@@ -38,9 +40,5 @@
|
||||
Additional services like the external PNG/SVG/Kroki links and "Save to Mermaid Chart" feature
|
||||
will share your diagram with the respective 3rd party service.
|
||||
</p>
|
||||
|
||||
<label class="btn btn-circle btn-ghost btn-sm absolute right-2 top-2" for="privacyModal">
|
||||
X
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { version } from 'mermaid/package.json';
|
||||
import QuestionCircleIcon from '~icons/material-symbols/help-outline-rounded';
|
||||
import ShieldIcon from '~icons/material-symbols/shield-lock-outline-rounded';
|
||||
import FloatingToolbar from './FloatingToolbar.svelte';
|
||||
import Privacy from './Privacy.svelte';
|
||||
import { Button } from './ui/button';
|
||||
import { Separator } from './ui/separator';
|
||||
</script>
|
||||
@@ -10,7 +10,7 @@
|
||||
<FloatingToolbar>
|
||||
<span class="text-sm font-semibold opacity-60">v{version}</span>
|
||||
<Button variant="ghost" size="icon" title="Privacy & Security">
|
||||
<ShieldIcon />
|
||||
<Privacy />
|
||||
</Button>
|
||||
|
||||
<Separator orientation="vertical" />
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { Dialog as DialogPrimitive, type WithoutChildrenOrChild } from 'bits-ui';
|
||||
import X from 'lucide-svelte/icons/x';
|
||||
import type { Snippet } from 'svelte';
|
||||
import * as Dialog from './index.js';
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
portalProps,
|
||||
children,
|
||||
...restProps
|
||||
}: WithoutChildrenOrChild<DialogPrimitive.ContentProps> & {
|
||||
portalProps?: DialogPrimitive.PortalProps;
|
||||
children: Snippet;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<Dialog.Portal {...portalProps}>
|
||||
<Dialog.Overlay />
|
||||
<DialogPrimitive.Content
|
||||
bind:ref
|
||||
class={cn(
|
||||
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
||||
className
|
||||
)}
|
||||
{...restProps}>
|
||||
{@render children?.()}
|
||||
<DialogPrimitive.Close
|
||||
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:text-muted-foreground">
|
||||
<X class="size-4" />
|
||||
<span class="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</Dialog.Portal>
|
||||
@@ -0,0 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: DialogPrimitive.DescriptionProps = $props();
|
||||
</script>
|
||||
|
||||
<DialogPrimitive.Description
|
||||
bind:ref
|
||||
class={cn("text-muted-foreground text-sm", className)}
|
||||
{...restProps}
|
||||
/>
|
||||
@@ -0,0 +1,20 @@
|
||||
<script lang="ts">
|
||||
import type { WithElementRef } from "bits-ui";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||
</script>
|
||||
|
||||
<div
|
||||
bind:this={ref}
|
||||
class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
||||
{...restProps}
|
||||
>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
@@ -0,0 +1,20 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import type { WithElementRef } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||
</script>
|
||||
|
||||
<div
|
||||
bind:this={ref}
|
||||
class={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)}
|
||||
{...restProps}
|
||||
>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
@@ -0,0 +1,19 @@
|
||||
<script lang="ts">
|
||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: DialogPrimitive.OverlayProps = $props();
|
||||
</script>
|
||||
|
||||
<DialogPrimitive.Overlay
|
||||
bind:ref
|
||||
class={cn(
|
||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80",
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
/>
|
||||
@@ -0,0 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: DialogPrimitive.TitleProps = $props();
|
||||
</script>
|
||||
|
||||
<DialogPrimitive.Title
|
||||
bind:ref
|
||||
class={cn("text-lg font-semibold leading-none tracking-tight", className)}
|
||||
{...restProps}
|
||||
/>
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||
|
||||
import Title from "./dialog-title.svelte";
|
||||
import Footer from "./dialog-footer.svelte";
|
||||
import Header from "./dialog-header.svelte";
|
||||
import Overlay from "./dialog-overlay.svelte";
|
||||
import Content from "./dialog-content.svelte";
|
||||
import Description from "./dialog-description.svelte";
|
||||
|
||||
const Root: typeof DialogPrimitive.Root = DialogPrimitive.Root;
|
||||
const Trigger: typeof DialogPrimitive.Trigger = DialogPrimitive.Trigger;
|
||||
const Close: typeof DialogPrimitive.Close = DialogPrimitive.Close;
|
||||
const Portal: typeof DialogPrimitive.Portal = DialogPrimitive.Portal;
|
||||
|
||||
export {
|
||||
Root,
|
||||
Title,
|
||||
Portal,
|
||||
Footer,
|
||||
Header,
|
||||
Trigger,
|
||||
Overlay,
|
||||
Content,
|
||||
Description,
|
||||
Close,
|
||||
//
|
||||
Root as Dialog,
|
||||
Title as DialogTitle,
|
||||
Portal as DialogPortal,
|
||||
Footer as DialogFooter,
|
||||
Header as DialogHeader,
|
||||
Trigger as DialogTrigger,
|
||||
Overlay as DialogOverlay,
|
||||
Content as DialogContent,
|
||||
Description as DialogDescription,
|
||||
Close as DialogClose,
|
||||
};
|
||||
@@ -1763,10 +1763,10 @@ bindings@^1.5.0:
|
||||
dependencies:
|
||||
file-uri-to-path "1.0.0"
|
||||
|
||||
bits-ui@^1.3.6:
|
||||
version "1.3.6"
|
||||
resolved "https://registry.yarnpkg.com/bits-ui/-/bits-ui-1.3.6.tgz#9b0fe5db7934db06fa0cea9b468251bfe991ca58"
|
||||
integrity sha512-0Ee7Ox5KqIBdio/+TG387Xlj6QJ0S7tHVS2K4DYiBHxBRbm6ni13i/pOoNDjeME6NOGUZxbSe4dNZIW3pGlxZA==
|
||||
bits-ui@^1.3.12:
|
||||
version "1.3.12"
|
||||
resolved "https://registry.yarnpkg.com/bits-ui/-/bits-ui-1.3.12.tgz#311d33e12fd619d97850500f9c4e719373d64e69"
|
||||
integrity sha512-RhPvg2e7mTQSXR9WMdsyR5eTC2DSa4ch5MT/TjIaN3suMJ3RGlbzYPNvf4n56Lgck3W4Xm+L4jSgrzTdynuM8Q==
|
||||
dependencies:
|
||||
"@floating-ui/core" "^1.6.4"
|
||||
"@floating-ui/dom" "^1.6.7"
|
||||
@@ -4523,10 +4523,10 @@ lru-cache@^6.0.0:
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
lucide-svelte@^0.477.0:
|
||||
version "0.477.0"
|
||||
resolved "https://registry.yarnpkg.com/lucide-svelte/-/lucide-svelte-0.477.0.tgz#85d80c9a7787b4b3ff8f5faed2f41182c8c4e303"
|
||||
integrity sha512-w/zj6/CXTtTizIeo8SuWGYu0u45CJ7cD2AtNzIObVHZrWXNgaIIX/2cI25wybjSmYHIi4pub2TLv/kNPKiB3ww==
|
||||
lucide-svelte@^0.479.0:
|
||||
version "0.479.0"
|
||||
resolved "https://registry.yarnpkg.com/lucide-svelte/-/lucide-svelte-0.479.0.tgz#680157ee44f9ed88e01539276556ba211292af7d"
|
||||
integrity sha512-epCj6WL86ykxg7oCQTmPEth5e11pwJUzIfG9ROUsWsTP+WPtb3qat+VmAjfx/r4TRW7memTFcbTPvMrZvKthqw==
|
||||
|
||||
lz-string@^1.5.0:
|
||||
version "1.5.0"
|
||||
|
||||
Reference in New Issue
Block a user