8 Commits

Author SHA1 Message Date
pheralb a488bd4c7a 🛠️ Update workflows to use Eslint for linting and set `PUBLIC_SVGL_VERSION` env variable
📦 Build / 🛠️ Build app (push) Has been cancelled
🧑‍🚀 Check / 📦 SVGs Size (push) Has been cancelled
🧑‍🚀 Check / ⚙️ Linting (push) Has been cancelled
2025-08-31 13:59:13 +01:00
pheralb 411ad69a8f 🛠️ Add nixpacks configuration for PNPM setup and build process 2025-08-31 13:48:10 +01:00
pheralb 68e399d99c 🎨 Design improvements 2025-08-31 13:43:53 +01:00
pheralb d06c87037a 🛠️ Improve svgCard component to support theme-based image rendering 2025-08-31 13:43:31 +01:00
pheralb 73bd5a4f78 🛠️ Create codeBlock UI component + setup shadcn/ui registry 2025-08-31 13:43:17 +01:00
pheralb 26b8f0a2ae 🛠️ Create custom svgl version component 2025-08-30 22:31:51 +01:00
pheralb 85e6bb33b8 🛠️ Update pnpm setup to version 10 in deploy API workflow 2025-08-30 16:26:09 +01:00
pheralb 2f3ef58218 🛠️ Remove version specification for pnpm setup in workflows 2025-08-30 16:25:56 +01:00
15 changed files with 217 additions and 55 deletions
+3 -3
View File
@@ -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
+8 -10
View File
@@ -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
+3 -3
View File
@@ -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
+20
View File
@@ -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"
+71
View File
@@ -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>
+2 -2
View File
@@ -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">
+8
View File
@@ -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}
+10 -20
View File
@@ -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} />
+9 -1
View File
@@ -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>
+41 -13
View File
@@ -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?.()}
-1
View File
@@ -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",
};
+2
View File
@@ -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?.()}