feat: remove v1 routes and libs

This commit is contained in:
2026-09-25 16:39:58 +05:00
parent 473b62ef53
commit 16d4288912
91 changed files with 181 additions and 11960 deletions
-176
View File
@@ -1,176 +0,0 @@
<script lang="ts">
import { resolve } from "$app/paths";
import { getTheme, initTheme, setTheme } from "$lib/theme.svelte";
import { LOCALES, type Locale } from "$lib/v1/i18n/dict";
import { getLocale, initLocale, setLocale } from "$lib/v1/i18n/locale.svelte";
import { t } from "$lib/v1/i18n/t";
import { onMount } from "svelte";
import "../../app_v1.css";
let { children } = $props();
onMount(() => {
initLocale();
initTheme();
});
const LANG_LABELS: Record<Locale, string> = { ru: "RU", en: "EN" };
</script>
<svelte:head>
<link rel="icon" href={`${resolve("/")}favicon.svg`} />
</svelte:head>
<div class="app">
<header>
<a href={resolve("/v1")} class="brand">easy-png-tools</a>
<nav aria-label={t("header.sectionsAria")}>
<a class="nav-link workspace-link" href={resolve("/v1")}>
{t("header.workspace")}
</a>
<a class="nav-link" href={resolve("/v1/list-tools")}>
{t("header.catalog")}
</a>
<div class="lang-switch" role="group" aria-label="Language / Язык">
{#each LOCALES as l (l)}
<button
type="button"
class="lang-btn"
class:active={getLocale() === l}
aria-pressed={getLocale() === l}
onclick={() => setLocale(l)}
>
{LANG_LABELS[l]}
</button>
{/each}
</div>
<div class="theme-switch" role="group" aria-label="Theme / Тема">
<button
type="button"
class="lang-btn"
class:active={getTheme() === "light"}
aria-pressed={getTheme() === "light"}
title={t("ui.themeLight")}
aria-label={t("ui.themeLight")}
onclick={() => setTheme("light")}
>
☀
</button>
<button
type="button"
class="lang-btn"
class:active={getTheme() === "dark"}
aria-pressed={getTheme() === "dark"}
title={t("ui.themeDark")}
aria-label={t("ui.themeDark")}
onclick={() => setTheme("dark")}
>
☾
</button>
</div>
</nav>
</header>
<main>
{@render children()}
</main>
<footer>
<p class="text-caption text-muted">{t("header.footerNote")}</p>
</footer>
</div>
<style>
.app {
min-height: 100dvh;
display: flex;
flex-direction: column;
}
header {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-3);
flex-wrap: wrap;
padding: var(--space-3) var(--space-4);
background: var(--surface);
border-bottom: 1px solid var(--border);
}
.brand {
font-weight: 700;
font-size: 1.1rem;
color: var(--text);
}
.brand:hover {
text-decoration: none;
color: var(--link);
}
nav {
display: flex;
gap: var(--space-3);
flex-wrap: wrap;
}
.nav-link {
color: var(--text-muted);
font-size: var(--text-s);
padding: var(--space-1) var(--space-2);
border-radius: var(--radius-s);
}
.nav-link:hover {
color: var(--link);
background: var(--bg);
text-decoration: none;
}
.lang-switch,
.theme-switch {
display: flex;
gap: 2px;
margin-left: var(--space-2);
padding: 2px;
border: 1px solid var(--border);
border-radius: var(--radius-s);
background: var(--bg);
}
.lang-btn {
border: none;
background: transparent;
color: var(--text-muted);
font-size: var(--text-s);
font-weight: 600;
padding: 2px 8px;
border-radius: calc(var(--radius-s) - 1px);
cursor: pointer;
}
.lang-btn:hover {
color: var(--link);
}
.lang-btn.active {
background: var(--accent);
color: var(--bg);
}
.workspace-link {
font-weight: 600;
color: var(--link);
}
main {
flex: 1;
width: 100%;
padding: var(--space-4) var(--space-5);
}
footer {
padding: var(--space-3) var(--space-4);
border-top: 1px solid var(--border);
text-align: center;
}
</style>
-119
View File
@@ -1,119 +0,0 @@
<script lang="ts">
import { t } from "$lib/v1/i18n/t";
import { toolTitle } from "$lib/v1/i18n/tool-strings";
import ToolPage from "$lib/v1/components/ToolPage.svelte";
import ToolSearch from "$lib/v1/components/search/ToolSearch.svelte";
import Button from "$lib/v1/components/ui/Button.svelte";
import { getTool } from "$lib/v1/registry";
const LAST_TOOL_KEY = "last-tool-id";
function loadLastToolId(): string | null {
if (typeof localStorage === "undefined") return null;
try {
const id = localStorage.getItem(LAST_TOOL_KEY);
return id !== null && getTool(id) ? id : null;
} catch {
return null;
}
}
let selectedId = $state<string | null>(null);
let restoreOnOpen = $state(false);
let lastToolId = $state<string | null>(loadLastToolId());
function openTool(id: string, restore = false) {
if (!getTool(id)) return;
selectedId = id;
restoreOnOpen = restore;
lastToolId = id;
if (typeof localStorage === "undefined") return;
try {
localStorage.setItem(LAST_TOOL_KEY, id);
} catch {
// приватный режим — просто не запоминаем
}
}
function closeTool() {
selectedId = null;
}
let selected = $derived(
selectedId !== null ? (getTool(selectedId) ?? null) : null,
);
</script>
<svelte:head>
<title>
{selected ? `${selected.title} — easy-png-tools` : t("home.defaultTitle")}
</title>
</svelte:head>
{#if !selected}
<section class="hero">
<h1>{t("home.heroTitle")}</h1>
<p class="lead text-muted">{t("home.heroLead")}</p>
<ToolSearch onSelect={(id) => openTool(id)} />
{#if lastToolId !== null && getTool(lastToolId)}
{@const restoreId = lastToolId}
<div class="restore-row">
<Button
variant="secondary"
fullWidth
onclick={() => openTool(restoreId, true)}
>
{t("home.restoreLast", {
title: getTool(restoreId) ? toolTitle(getTool(restoreId)!) : "",
})}
</Button>
</div>
{/if}
</section>
{:else}
<section class="workbench">
<button
type="button"
class="back text-caption text-muted"
onclick={closeTool}
>
{t("home.changeTool")}
</button>
{#key selectedId}
<ToolPage tool={selected} restoreChain={restoreOnOpen} />
{/key}
</section>
{/if}
<style>
.hero {
text-align: center;
padding-top: var(--space-5);
}
h1 {
margin-bottom: var(--space-2);
}
.lead {
max-width: 40rem;
margin: 0 auto var(--space-4);
}
.restore-row {
max-width: 36rem;
margin: var(--space-2) auto 0;
}
.back {
display: inline-block;
margin-bottom: var(--space-3);
border: 0;
background: none;
cursor: pointer;
}
.back:hover {
color: var(--link);
}
</style>
-40
View File
@@ -1,40 +0,0 @@
<script lang="ts">
import ToolPage from "$lib/v1/components/ToolPage.svelte";
import { getTool } from "$lib/v1/registry";
const base = getTool("linear-gradient-png")!;
</script>
<svelte:head>
<title>Mockup: цепочка инструментов — easy-png-tools</title>
<meta name="robots" content="noindex, nofollow" />
</svelte:head>
<section class="demo">
<ToolPage
tool={base}
stageVariant="inline"
presetBaseValues={{
width: 520,
height: 340,
fromColor: "#e5484d",
toColor: "#fbbf24",
direction: "horizontal",
}}
presetChain={[
{
toolId: "remove-background-png",
values: { color: "#fbbf24", tolerance: 10, outerOnly: true, smooth: 2 },
},
{ toolId: "add-stroke-png", values: { color: "#2563eb", thickness: 8 } },
{ toolId: "round-corners-png", values: { radius: 28 } },
]}
/>
</section>
<style>
.demo {
max-width: 100rem;
margin: 0 auto;
}
</style>
-83
View File
@@ -1,83 +0,0 @@
<script lang="ts">
import { resolve } from "$app/paths";
import { t } from "$lib/v1/i18n/t";
import { toolDescription, toolTitle } from "$lib/v1/i18n/tool-strings";
import { CATEGORIES } from "$lib/v1/categories";
import ToolCard from "$lib/v1/components/search/ToolCard.svelte";
import { TOOLS } from "$lib/v1/registry";
</script>
<svelte:head>
<title>{t("catalog.pageTitle")}</title>
<meta name="description" content={t("catalog.metaDescription")} />
</svelte:head>
<h1>{t("catalog.heading")}</h1>
<p class="lead text-muted">{t("catalog.lead", { count: TOOLS.length })}</p>
{#each CATEGORIES as category (category)}
{@const categoryTools = TOOLS.filter((tool) => tool.category === category)}
{#if categoryTools.length > 0}
<section
id={category}
class="category"
aria-labelledby="{category}-heading"
>
<h2 id="{category}-heading" class="heading-section">
{t(`categories.${category}`)}
</h2>
<div class="grid">
{#each categoryTools as tool (tool.id)}
<div class="panel">
<ToolCard
toolId={tool.id}
title={toolTitle(tool)}
description={toolDescription(tool)}
href={resolve(`/tools/${tool.id}`)}
/>
</div>
{/each}
</div>
</section>
{/if}
{/each}
<style>
h1 {
margin-bottom: var(--space-1);
}
.lead {
max-width: 48rem;
margin-bottom: var(--space-5);
}
.category {
margin-bottom: var(--space-5);
scroll-margin-top: 5rem;
}
h2 {
margin-bottom: var(--space-3);
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
gap: var(--space-3);
}
.grid > .panel {
padding: var(--space-2) var(--space-2) var(--space-3);
transition:
border-color var(--transition-fast),
box-shadow var(--transition-fast),
transform var(--transition-fast);
}
.grid > .panel:hover {
border-color: var(--accent);
box-shadow: var(--shadow-card);
transform: translateY(-1px);
}
</style>
-23
View File
@@ -1,23 +0,0 @@
<script lang="ts">
import { t } from "$lib/v1/i18n/t";
import { toolDescription, toolTitle } from "$lib/v1/i18n/tool-strings";
import ToolPage from "$lib/v1/components/ToolPage.svelte";
import { getTool } from "$lib/v1/registry";
let { data } = $props();
const tool = $derived(getTool(data.id));
</script>
<svelte:head>
<title
>{tool ? toolTitle(tool) : t("toolPage.fallbackTitle")} — easy-png-tools</title
>
{#if tool}
<meta name="description" content={toolDescription(tool)} />
{/if}
</svelte:head>
{#if tool}
<ToolPage {tool} />
{/if}
-15
View File
@@ -1,15 +0,0 @@
import { t } from "$lib/v1/i18n/t";
import { getTool, TOOLS } from "$lib/v1/registry";
import { error } from "@sveltejs/kit";
import type { EntryGenerator, PageLoad } from "./$types";
export const entries: EntryGenerator = () =>
TOOLS.map((tool) => ({ id: tool.id }));
export const load: PageLoad = ({ params }) => {
const tool = getTool(params.id);
if (!tool) {
error(404, t("errors.notFound"));
}
return { id: tool.id };
};