mirror of
https://github.com/Ku6epXBOCTuK/easy-png-tools.git
synced 2026-11-13 17:08:20 +00:00
feat: breadcrumbs, related tools
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
<script lang="ts">
|
||||
import { resolve } from "$app/paths";
|
||||
import { pageTitle } from "$lib/i18n/schema-tool-strings";
|
||||
import { t } from "$lib/i18n/t";
|
||||
import type { Page } from "$lib/registry";
|
||||
import { ChevronRight } from "@lucide/svelte";
|
||||
|
||||
interface Props {
|
||||
page: Page;
|
||||
}
|
||||
let { page }: Props = $props();
|
||||
|
||||
const categoryLabel = $derived(t(`categories.${page.category}`));
|
||||
const title = $derived(pageTitle(page));
|
||||
</script>
|
||||
|
||||
<!-- Middle crumb is plain text: a category has no address of its own until the
|
||||
category hubs land (docs/plan-seo.md S3c), then it becomes a link here. -->
|
||||
<nav class="crumbs" aria-label={t("toolPage.breadcrumbAria")}>
|
||||
<a href={resolve("/list-tools")}>{t("toolPage.breadcrumbCatalog")}</a>
|
||||
<ChevronRight size={13} aria-hidden="true" />
|
||||
<span>{categoryLabel}</span>
|
||||
<ChevronRight size={13} aria-hidden="true" />
|
||||
<span class="current" aria-current="page">{title}</span>
|
||||
</nav>
|
||||
|
||||
<style>
|
||||
.crumbs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-s);
|
||||
flex-wrap: wrap;
|
||||
max-width: var(--size-content-max-wide);
|
||||
padding: var(--space-xxxl) clamp(var(--space-m), 4vw, var(--space-xxxl)) 0;
|
||||
font: var(--font-size-s) var(--font-mono);
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
a {
|
||||
color: var(--color-text-muted);
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
color: var(--color-main);
|
||||
}
|
||||
.current {
|
||||
color: var(--color-text);
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { pageSeo } from "$lib/i18n/schema-tool-strings";
|
||||
import { relatedPages } from "$lib/catalog";
|
||||
import ToolCard from "$lib/components/catalog/ToolCard.svelte";
|
||||
import {
|
||||
pageDescription,
|
||||
pageSeo,
|
||||
pageTitle,
|
||||
} from "$lib/i18n/schema-tool-strings";
|
||||
import { t } from "$lib/i18n/t";
|
||||
import type { Page } from "$lib/registry";
|
||||
import { toolIcon } from "$lib/tool-icons";
|
||||
|
||||
interface Props {
|
||||
page: Page;
|
||||
@@ -9,6 +16,7 @@
|
||||
let { page }: Props = $props();
|
||||
|
||||
const seo = $derived(pageSeo(page));
|
||||
const related = $derived(relatedPages(page, 6));
|
||||
</script>
|
||||
|
||||
<!-- Below the tool, not above it: the workspace is what the visitor came for,
|
||||
@@ -33,6 +41,21 @@
|
||||
</details>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<!-- Internal links: the only way a crawler reaches the neighbours of
|
||||
this page, so the block stays derived from the category, never a
|
||||
hand-picked list. -->
|
||||
<h2>{t("toolPage.relatedHeading")}</h2>
|
||||
<div class="related">
|
||||
{#each related as item (item.slug)}
|
||||
<ToolCard
|
||||
title={pageTitle(item)}
|
||||
slug={item.slug}
|
||||
description={pageDescription(item)}
|
||||
icon={toolIcon(item.slug)}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
@@ -91,9 +114,17 @@
|
||||
font-size: var(--font-size-m);
|
||||
line-height: 1.6;
|
||||
}
|
||||
.related {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: var(--space-l);
|
||||
}
|
||||
@media (--bp-tablet) {
|
||||
.long {
|
||||
font-size: var(--font-size-m);
|
||||
}
|
||||
.related {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<script lang="ts">
|
||||
import Button from "$lib/components/ui/Button.svelte";
|
||||
import ChipButton from "$lib/components/ui/ChipButton.svelte";
|
||||
import Toggle from "$lib/components/ui/Toggle.svelte";
|
||||
import { ButtonVariantDefine } from "$lib/components/ui/define";
|
||||
import { isFav, toggleFav } from "$lib/favorites.svelte";
|
||||
import { Star } from "@lucide/svelte";
|
||||
import { DragDropProvider } from "@dnd-kit/svelte";
|
||||
import { debounce } from "$lib/core/debounce";
|
||||
import { cachedDataUrl } from "$lib/core/io";
|
||||
import type { PixelImage } from "$lib/core/types";
|
||||
import { isFav, toggleFav } from "$lib/favorites.svelte";
|
||||
import {
|
||||
chainStepTitle,
|
||||
chainWarningNotice,
|
||||
@@ -17,8 +17,8 @@
|
||||
import { t } from "$lib/i18n/t";
|
||||
import { moveStep, type ChainStep } from "$lib/pipeline.svelte";
|
||||
import { getTool, type Page, type Tool } from "$lib/registry";
|
||||
import ChipButton from "$lib/components/ui/ChipButton.svelte";
|
||||
import Toggle from "$lib/components/ui/Toggle.svelte";
|
||||
import { DragDropProvider } from "@dnd-kit/svelte";
|
||||
import { Star } from "@lucide/svelte";
|
||||
import AddStepButton from "./AddStepButton.svelte";
|
||||
import PartsGrid from "./PartsGrid.svelte";
|
||||
import PreviewTile from "./PreviewTile.svelte";
|
||||
@@ -32,8 +32,8 @@
|
||||
import { createChainHost } from "./chain-host.svelte";
|
||||
import { createOutputControls } from "./output-controls.svelte";
|
||||
import { hasPreviewResult } from "./schema-preview-model";
|
||||
import { createSchemaToolRunner } from "./schema-tool-runner.svelte";
|
||||
import type { DisplayError } from "./schema-tool-runner.svelte";
|
||||
import { createSchemaToolRunner } from "./schema-tool-runner.svelte";
|
||||
import {
|
||||
createSchemaToolState,
|
||||
toolSchemaOf,
|
||||
@@ -483,8 +483,8 @@
|
||||
|
||||
<style>
|
||||
.schema-tool {
|
||||
padding: calc(var(--space-xxxl) + var(--space-l))
|
||||
clamp(var(--space-m), 4vw, var(--space-xxxl));
|
||||
padding: var(--space-l) clamp(var(--space-m), 4vw, var(--space-xxxl))
|
||||
calc(var(--space-xxxl) + var(--space-l));
|
||||
flex: 1;
|
||||
}
|
||||
.header {
|
||||
|
||||
Reference in New Issue
Block a user