mirror of
https://github.com/pheralb/svgl.git
synced 2025-12-29 08:01:36 +08:00
Compare commits
8 Commits
de110ef3f6
...
a488bd4c7a
| Author | SHA1 | Date | |
|---|---|---|---|
| a488bd4c7a | |||
| 411ad69a8f | |||
| 68e399d99c | |||
| d06c87037a | |||
| 73bd5a4f78 | |||
| 26b8f0a2ae | |||
| 85e6bb33b8 | |||
| 2f3ef58218 |
@@ -13,10 +13,8 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup pnpm 10
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
@@ -36,3 +34,5 @@ jobs:
|
||||
|
||||
- name: Build app
|
||||
run: pnpm build
|
||||
env:
|
||||
PUBLIC_SVGL_VERSION: v5
|
||||
|
||||
@@ -11,22 +11,22 @@ on:
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
vitest:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
name: ⚡ Testing with Vitest
|
||||
name: ⚙️ Linting
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup pnpm 10
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Run Vitest
|
||||
run: pnpm test
|
||||
- name: Run Eslint
|
||||
run: pnpm lint
|
||||
env:
|
||||
PUBLIC_SVGL_VERSION: v5
|
||||
|
||||
svgs-size:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -34,10 +34,8 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup pnpm 10
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Install utility dependencies
|
||||
run: pnpm install
|
||||
|
||||
@@ -12,10 +12,10 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup pnpm 9
|
||||
uses: pnpm/action-setup@v2
|
||||
- name: Setup pnpm 10
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
version: 10
|
||||
|
||||
- name: Install global dependencies
|
||||
run: pnpm install
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
[variables]
|
||||
NODE_VERSION = "22.17.0"
|
||||
PNPM_VERSION = "10.13.1"
|
||||
|
||||
[providers.node]
|
||||
version = "22.17.0"
|
||||
|
||||
[phases.setup]
|
||||
cmds = ["npm install -g pnpm@10.13.1"]
|
||||
|
||||
[phases.install]
|
||||
cmds = ["pnpm install --frozen-lockfile"]
|
||||
|
||||
[phases.build]
|
||||
# Build command using PNPM
|
||||
cmds = ["pnpm run build"]
|
||||
|
||||
[start]
|
||||
# Start command using PNPM
|
||||
cmd = "node build"
|
||||
@@ -0,0 +1,71 @@
|
||||
<script lang="ts">
|
||||
import type { Component, Snippet, SvelteComponent } from "svelte";
|
||||
|
||||
import { cn } from "@/utils/cn";
|
||||
import CopyIcon from "@lucide/svelte/icons/copy";
|
||||
import CheckIcon from "@lucide/svelte/icons/check";
|
||||
import { clipboard } from "@/utils/clipboard";
|
||||
|
||||
interface Props {
|
||||
code: string;
|
||||
className?: string;
|
||||
Icon?: Component;
|
||||
copyDuration?: number;
|
||||
}
|
||||
|
||||
let { Icon, className, code, copyDuration = 2000 }: Props = $props();
|
||||
let copied = $state(false);
|
||||
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
const handleCopy = async () => {
|
||||
try {
|
||||
await clipboard(code);
|
||||
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
copied = true;
|
||||
timeoutId = setTimeout(() => {
|
||||
copied = false;
|
||||
timeoutId = null;
|
||||
}, copyDuration);
|
||||
} catch (error) {
|
||||
copied = false;
|
||||
}
|
||||
};
|
||||
|
||||
$effect(() => {
|
||||
return () => {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<div
|
||||
class={cn(
|
||||
"relative flex items-center space-x-2 rounded-md border border-neutral-200 p-2.5 dark:border-neutral-800",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<button
|
||||
class="absolute right-2 transition-colors hover:text-neutral-600 dark:hover:text-neutral-400"
|
||||
onclick={handleCopy}
|
||||
disabled={copied}
|
||||
title={copied ? "Copied" : "Copy code"}
|
||||
>
|
||||
{#if copied}
|
||||
<CheckIcon size={14} />
|
||||
{:else}
|
||||
<CopyIcon size={14} />
|
||||
{/if}
|
||||
</button>
|
||||
{#if Icon}
|
||||
<Icon size={14} class="text-neutral-500" />
|
||||
{/if}
|
||||
<code class="pr-8 font-mono text-sm select-all">
|
||||
{code}
|
||||
</code>
|
||||
</div>
|
||||
@@ -9,8 +9,8 @@
|
||||
import Twitter from "@/components/logos/twitter.svelte";
|
||||
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import Badge from "@/components/ui/badge/badge.svelte";
|
||||
import { buttonVariants } from "@/components/ui/button";
|
||||
import SvglVersion from "@/components/svglVersion.svelte";
|
||||
import SendIcon from "@/components/ui/moving-icons/send-icon.svelte";
|
||||
|
||||
interface HeaderProps {
|
||||
@@ -37,7 +37,7 @@
|
||||
<Svgl size={28} />
|
||||
<h2 class="font-onest text-xl font-medium tracking-tight">svgl</h2>
|
||||
</a>
|
||||
<Badge variant="outline">{globals.currentVersion}</Badge>
|
||||
<SvglVersion />
|
||||
</div>
|
||||
<div class="flex h-8 items-center">
|
||||
<div class="flex items-center space-x-0.5">
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<script>
|
||||
import { PUBLIC_SVGL_VERSION } from "$env/static/public";
|
||||
import Badge from "@/components/ui/badge/badge.svelte";
|
||||
</script>
|
||||
|
||||
{#if PUBLIC_SVGL_VERSION}
|
||||
<Badge variant="outline">{PUBLIC_SVGL_VERSION}</Badge>
|
||||
{/if}
|
||||
@@ -1,11 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { clipboard } from "@/utils/clipboard";
|
||||
|
||||
import CopyIcon from "@lucide/svelte/icons/copy";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Shadcn from "@/components/logos/shadcn.svelte";
|
||||
import SelectPkgManager from "@/components/selectPkgManager.svelte";
|
||||
|
||||
import { pkgManager, type PackageManager } from "@/stores/pkgManager.store";
|
||||
import Shadcn from "../logos/shadcn.svelte";
|
||||
import CodeBlock from "@/components/codeBlock.svelte";
|
||||
import SetupShadcnRegistry from "@/components/svgs/setupShadcnRegistry.svelte";
|
||||
|
||||
interface Props {
|
||||
svgTitle: string;
|
||||
@@ -26,24 +26,14 @@
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, "-")
|
||||
.replace(/[^a-z0-9-]/g, "");
|
||||
|
||||
const handleCopy = () => {
|
||||
clipboard(`${shadcnCommand} @svgl/${svgFormatTitle}`);
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="flex items-center justify-between space-x-2">
|
||||
<SetupShadcnRegistry>
|
||||
<Button variant="outline" size="sm">
|
||||
<span>Setup Registry</span>
|
||||
</Button>
|
||||
</SetupShadcnRegistry>
|
||||
<SelectPkgManager />
|
||||
<Button variant="outline" onclick={handleCopy} size="sm">
|
||||
<CopyIcon size={14} />
|
||||
<span>Copy</span>
|
||||
</Button>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center space-x-2 rounded-md border border-neutral-200 p-2.5 dark:border-neutral-800"
|
||||
>
|
||||
<Shadcn size={14} />
|
||||
<code class="font-mono text-sm select-all">
|
||||
{shadcnCommand} @svgl/{svgFormatTitle}
|
||||
</code>
|
||||
</div>
|
||||
<CodeBlock code={`${shadcnCommand} @svgl/${svgFormatTitle}`} Icon={Shadcn} />
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
</Dialog.Header>
|
||||
<div
|
||||
class={cn(
|
||||
"flex h-full flex-col space-y-2 pt-4 pb-0.5",
|
||||
"flex h-full flex-col space-y-2 pt-2 pb-0.5",
|
||||
"md:flex-row md:items-center md:justify-center md:space-y-0 md:space-x-2",
|
||||
)}
|
||||
>
|
||||
@@ -130,6 +130,7 @@
|
||||
class="my-4 h-8"
|
||||
/>
|
||||
<Button
|
||||
class="justify-start"
|
||||
title="Download logo"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -151,6 +152,7 @@
|
||||
class="my-4 h-10"
|
||||
/>
|
||||
<Button
|
||||
class="justify-start"
|
||||
title="Logo with light & dark variants"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -167,6 +169,7 @@
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
class="justify-start"
|
||||
title="Download light variant"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -181,6 +184,7 @@
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
class="justify-start"
|
||||
title="Download dark variant"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -204,6 +208,7 @@
|
||||
class="my-4 h-8"
|
||||
/>
|
||||
<Button
|
||||
class="justify-start"
|
||||
title="Download Wordmark logo"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -229,6 +234,7 @@
|
||||
class="my-4 h-10"
|
||||
/>
|
||||
<Button
|
||||
class="justify-start"
|
||||
title="Download Wordmark light variant"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -247,6 +253,7 @@
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
class="justify-start"
|
||||
title="Download Wordmark light variant"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
@@ -261,6 +268,7 @@
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
class="justify-start"
|
||||
title="Download Wordmark dark variant"
|
||||
variant="outline"
|
||||
onclick={() => {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<script lang="ts">
|
||||
import type { Snippet } from "svelte";
|
||||
import * as Dialog from "@/components/ui/dialog";
|
||||
import CodeBlock from "@/components/codeBlock.svelte";
|
||||
|
||||
interface Props {
|
||||
children: Snippet;
|
||||
}
|
||||
|
||||
let { children }: Props = $props();
|
||||
|
||||
let registryCode = `
|
||||
"registries": {
|
||||
"@svgl": "https://svgl.app/r/{name}.json"
|
||||
}
|
||||
`;
|
||||
</script>
|
||||
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>
|
||||
{@render children?.()}
|
||||
</Dialog.Trigger>
|
||||
<Dialog.Content class="text-sm">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Setup shadcn/ui registry</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Use the code below to configure the @svgl registry for your project.
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
<p>
|
||||
1. Copy and paste the code into
|
||||
<span class="font-mono">components.json</span>:
|
||||
</p>
|
||||
<CodeBlock code={registryCode} />
|
||||
<p class="mt-2">2. Then use the following command to add SVGs:</p>
|
||||
<CodeBlock code={`npx shadcn@latest add @svgl/[svg-name]`} />
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { iSVG } from "@/types/svg";
|
||||
import { cn } from "@/utils/cn";
|
||||
import { mode } from "mode-watcher";
|
||||
|
||||
// Icons:
|
||||
import XIcon from "@lucide/svelte/icons/x";
|
||||
@@ -31,6 +32,7 @@
|
||||
// States:
|
||||
let wordmarkSvg = $state<boolean>(false);
|
||||
let moreTagsOptions = $state<boolean>(false);
|
||||
let changeThemeMode = $state<boolean>(false);
|
||||
|
||||
// Icon Stroke & Size:
|
||||
let iconStroke = 1.8;
|
||||
@@ -68,20 +70,46 @@
|
||||
</div>
|
||||
<!-- Image -->
|
||||
{#if wordmarkSvg == true && svgInfo.wordmark !== undefined}
|
||||
{#if changeThemeMode}
|
||||
<img
|
||||
class={cn("block", globalImageStyles)}
|
||||
src={typeof svgInfo.wordmark !== "string"
|
||||
? mode.current === "dark"
|
||||
? svgInfo.wordmark?.light || ""
|
||||
: svgInfo.wordmark?.dark || ""
|
||||
: svgInfo.wordmark || ""}
|
||||
alt={svgInfo.title}
|
||||
title={svgInfo.title}
|
||||
loading="lazy"
|
||||
/>
|
||||
{:else}
|
||||
<img
|
||||
class={cn("hidden dark:block", globalImageStyles)}
|
||||
src={typeof svgInfo.wordmark !== "string"
|
||||
? svgInfo.wordmark?.dark || ""
|
||||
: svgInfo.wordmark || ""}
|
||||
alt={svgInfo.title}
|
||||
title={svgInfo.title}
|
||||
loading="lazy"
|
||||
/>
|
||||
<img
|
||||
class={cn("block dark:hidden", globalImageStyles)}
|
||||
src={typeof svgInfo.wordmark !== "string"
|
||||
? svgInfo.wordmark?.light || ""
|
||||
: svgInfo.wordmark || ""}
|
||||
alt={svgInfo.title}
|
||||
title={svgInfo.title}
|
||||
loading="lazy"
|
||||
/>
|
||||
{/if}
|
||||
{:else if changeThemeMode}
|
||||
<img
|
||||
class={cn("hidden dark:block", globalImageStyles)}
|
||||
src={typeof svgInfo.wordmark !== "string"
|
||||
? svgInfo.wordmark?.dark || ""
|
||||
: svgInfo.wordmark || ""}
|
||||
alt={svgInfo.title}
|
||||
title={svgInfo.title}
|
||||
loading="lazy"
|
||||
/>
|
||||
<img
|
||||
class={cn("block dark:hidden", globalImageStyles)}
|
||||
src={typeof svgInfo.wordmark !== "string"
|
||||
? svgInfo.wordmark?.light || ""
|
||||
: svgInfo.wordmark || ""}
|
||||
class={cn("block", globalImageStyles)}
|
||||
src={typeof svgInfo.route !== "string"
|
||||
? mode.current === "dark"
|
||||
? svgInfo.route.light
|
||||
: svgInfo.route.dark
|
||||
: svgInfo.route}
|
||||
alt={svgInfo.title}
|
||||
title={svgInfo.title}
|
||||
loading="lazy"
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
bind:ref
|
||||
data-slot="dialog-content"
|
||||
class={cn(
|
||||
"fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border border-neutral-200 bg-white p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg dark:border-neutral-800 dark:bg-neutral-900",
|
||||
"fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-2 rounded-lg border border-neutral-200 bg-white p-6 shadow-lg duration-200 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg dark:border-neutral-800 dark:bg-neutral-900",
|
||||
className,
|
||||
)}
|
||||
{...restProps}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<div
|
||||
bind:this={ref}
|
||||
data-slot="dialog-header"
|
||||
class={cn("flex flex-col gap-2 text-center sm:text-left", className)}
|
||||
class={cn("mb-2 flex flex-col gap-1 text-center sm:text-left", className)}
|
||||
{...restProps}
|
||||
>
|
||||
{@render children?.()}
|
||||
|
||||
@@ -4,5 +4,4 @@ export const globals = {
|
||||
twitterUrl: "https://x.com/pheralb_",
|
||||
submitUrl:
|
||||
"https://github.com/pheralb/svgl?tab=readme-ov-file#-getting-started",
|
||||
currentVersion: "beta",
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
import { ModeWatcher } from "mode-watcher";
|
||||
import Sidebar from "@/components/layout/sidebar.svelte";
|
||||
import ViewTransitions from "@/components/viewTransitions.svelte";
|
||||
import Sonner from "@/components/ui/sonner/sonner.svelte";
|
||||
|
||||
// SSR Data:
|
||||
let { data, children }: LayoutProps = $props();
|
||||
@@ -18,6 +19,7 @@
|
||||
|
||||
<ModeWatcher />
|
||||
<ViewTransitions />
|
||||
<Sonner />
|
||||
<Header githubStars={data?.stars} />
|
||||
<Sidebar>
|
||||
{@render children?.()}
|
||||
|
||||
Reference in New Issue
Block a user