chore(website): share page metadata, model screenshot devices as records, honor reduced motion
Home, privacy, and scan each repeated the same 13 title/canonical/Open Graph/Twitter tags; PageMetadata now emits them once with route-specific title, description, url, and an optional noindex. Screenshots keeps one record per device instead of four parallel arrays plus a lookup table. FAQ hash jumps and screenshot arrows forced behavior: 'smooth' from JS, which bypasses the prefers-reduced-motion override in layout.css; both now defer to CSS scroll-behavior. Removes the unused adapter-auto dependency.
This commit is contained in:
@@ -9,7 +9,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/json": "^2.2.474",
|
||||
"@sveltejs/adapter-auto": "^7.0.0",
|
||||
"@sveltejs/enhanced-img": "^0.10.4",
|
||||
"@sveltejs/kit": "^2.70.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
||||
@@ -215,8 +214,6 @@
|
||||
|
||||
"@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.11", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-LFuZUkjJ9iF7JZye/aG5XM0SFcQ5VyL0oVX4WJ9dc0Va3R3s0OauX1BESVCb+YN/ol8TAfqGDDAQsTG627Y5kw=="],
|
||||
|
||||
"@sveltejs/adapter-auto": ["@sveltejs/adapter-auto@7.0.0", "", { "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-ImDWaErTOCkRS4Gt+5gZuymKFBobnhChXUZ9lhUZLahUgvA4OOvRzi3sahzYgbxGj5nkA6OV0GAW378+dl/gyw=="],
|
||||
|
||||
"@sveltejs/adapter-static": ["@sveltejs/adapter-static@3.0.10", "", { "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-7D9lYFWJmB7zxZyTE/qxjksvMqzMuYrrsyh1f4AlZqeZeACPRySjbC3aFiY55wb1tWUaKOQG9PVbm74JcN2Iew=="],
|
||||
|
||||
"@sveltejs/enhanced-img": ["@sveltejs/enhanced-img@0.10.4", "", { "dependencies": { "magic-string": "^0.30.5", "sharp": "^0.34.1", "svelte-parse-markup": "^0.1.5", "vite-imagetools": "^9.0.3", "zimmerframe": "^1.1.2" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^6.0.0 || ^7.0.0", "svelte": "^5.0.0", "vite": "^6.3.0 || >=7.0.0" } }, "sha512-Am5nmAKUo7Nboqq7Dhtfn7dcXA087d7gIz6Vecn1opB41aJ680+0q9U9KvEcMgduOyeiwckTIOQOx4Mmq9GcvA=="],
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/json": "^2.2.474",
|
||||
"@sveltejs/adapter-auto": "^7.0.0",
|
||||
"@sveltejs/enhanced-img": "^0.10.4",
|
||||
"@sveltejs/kit": "^2.70.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
if (hashIndex !== -1) {
|
||||
openIndex = hashIndex;
|
||||
requestAnimationFrame(() => {
|
||||
document.getElementById(hash)?.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||
document.getElementById(hash)?.scrollIntoView({ block: "center" });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<script lang="ts">
|
||||
const image = 'https://plezy.app/og/plezy-social.png';
|
||||
|
||||
let {
|
||||
title,
|
||||
description,
|
||||
url,
|
||||
noindex = false,
|
||||
}: { title: string; description: string; url: string; noindex?: boolean } = $props();
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{title}</title>
|
||||
<meta name="description" content={description} />
|
||||
{#if noindex}
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
{/if}
|
||||
<link rel="canonical" href={url} />
|
||||
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="Plezy" />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:url" content={url} />
|
||||
<meta property="og:image" content={image} />
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
<meta name="twitter:image" content={image} />
|
||||
</svelte:head>
|
||||
@@ -27,75 +27,62 @@
|
||||
type DeviceType = 'phone' | 'tablet' | 'desktop' | 'tv';
|
||||
type DeviceIconComponent = typeof DevicePhoneIcon | typeof DeviceTabletIcon | typeof DesktopIcon | typeof TvIcon;
|
||||
|
||||
const devices: { id: DeviceType; icon: DeviceIconComponent; label: string }[] = [
|
||||
{ id: 'phone', icon: DevicePhoneIcon, label: 'Phone' },
|
||||
{ id: 'tablet', icon: DeviceTabletIcon, label: 'Tablet' },
|
||||
{ id: 'desktop', icon: DesktopIcon, label: 'Desktop' },
|
||||
{ id: 'tv', icon: TvIcon, label: 'TV' },
|
||||
];
|
||||
|
||||
const phoneShots = [
|
||||
{ image: phoneHomeImage, alt: 'Plezy home screen' },
|
||||
{ image: phoneLibraryImage, alt: 'Plezy library view' },
|
||||
{ image: phoneMdImage, alt: 'Plezy media details' },
|
||||
{ image: phoneSearchImage, alt: 'Plezy search' },
|
||||
];
|
||||
|
||||
const tabletShots = [
|
||||
{ image: tabletHomeImage, alt: 'Plezy on tablet - home' },
|
||||
{ image: tabletLibraryImage, alt: 'Plezy on tablet - library' },
|
||||
{ image: tabletMdImage, alt: 'Plezy on tablet - media details' },
|
||||
{ image: tabletPlayerImage, alt: 'Plezy on tablet - video player' },
|
||||
];
|
||||
|
||||
const desktopShots = [
|
||||
{ image: desktopHomeImage, alt: 'Plezy on desktop - home' },
|
||||
{ image: desktopLibraryImage, alt: 'Plezy on desktop - library' },
|
||||
{ image: desktopMdImage, alt: 'Plezy on desktop - media details' },
|
||||
{ image: desktopPlayerImage, alt: 'Plezy on desktop - video player' },
|
||||
];
|
||||
|
||||
const tvShots = [
|
||||
{ image: tvHomeImage, alt: 'Plezy on TV - home' },
|
||||
{ image: tvLibraryImage, alt: 'Plezy on TV - library' },
|
||||
{ image: tvMdImage, alt: 'Plezy on TV - media details' },
|
||||
{ image: tvPlayerImage, alt: 'Plezy on TV - video player' },
|
||||
];
|
||||
|
||||
const screenshots: Record<
|
||||
DeviceType,
|
||||
const devices: {
|
||||
id: DeviceType;
|
||||
icon: DeviceIconComponent;
|
||||
label: string;
|
||||
sizes: string;
|
||||
shots: { image: typeof phoneHomeImage; alt: string }[];
|
||||
}[] = [
|
||||
{
|
||||
shots: typeof phoneShots;
|
||||
frameClass: string;
|
||||
sizes: string;
|
||||
ariaLabel: string;
|
||||
}
|
||||
> = {
|
||||
phone: {
|
||||
shots: phoneShots,
|
||||
frameClass: 'phone-frame',
|
||||
id: 'phone',
|
||||
icon: DevicePhoneIcon,
|
||||
label: 'Phone',
|
||||
sizes: '(min-width: 1024px) 214px, 187px',
|
||||
ariaLabel: 'Phone screenshots',
|
||||
shots: [
|
||||
{ image: phoneHomeImage, alt: 'Plezy home screen' },
|
||||
{ image: phoneLibraryImage, alt: 'Plezy library view' },
|
||||
{ image: phoneMdImage, alt: 'Plezy media details' },
|
||||
{ image: phoneSearchImage, alt: 'Plezy search' },
|
||||
],
|
||||
},
|
||||
tablet: {
|
||||
shots: tabletShots,
|
||||
frameClass: 'tablet-frame',
|
||||
{
|
||||
id: 'tablet',
|
||||
icon: DeviceTabletIcon,
|
||||
label: 'Tablet',
|
||||
sizes: '(min-width: 1024px) 768px, 672px',
|
||||
ariaLabel: 'Tablet screenshots',
|
||||
shots: [
|
||||
{ image: tabletHomeImage, alt: 'Plezy on tablet - home' },
|
||||
{ image: tabletLibraryImage, alt: 'Plezy on tablet - library' },
|
||||
{ image: tabletMdImage, alt: 'Plezy on tablet - media details' },
|
||||
{ image: tabletPlayerImage, alt: 'Plezy on tablet - video player' },
|
||||
],
|
||||
},
|
||||
desktop: {
|
||||
shots: desktopShots,
|
||||
frameClass: 'desktop-frame',
|
||||
{
|
||||
id: 'desktop',
|
||||
icon: DesktopIcon,
|
||||
label: 'Desktop',
|
||||
sizes: '(min-width: 1024px) 768px, 672px',
|
||||
ariaLabel: 'Desktop screenshots',
|
||||
shots: [
|
||||
{ image: desktopHomeImage, alt: 'Plezy on desktop - home' },
|
||||
{ image: desktopLibraryImage, alt: 'Plezy on desktop - library' },
|
||||
{ image: desktopMdImage, alt: 'Plezy on desktop - media details' },
|
||||
{ image: desktopPlayerImage, alt: 'Plezy on desktop - video player' },
|
||||
],
|
||||
},
|
||||
tv: {
|
||||
shots: tvShots,
|
||||
frameClass: 'tv-frame',
|
||||
{
|
||||
id: 'tv',
|
||||
icon: TvIcon,
|
||||
label: 'TV',
|
||||
sizes: '(min-width: 1024px) 854px, 747px',
|
||||
ariaLabel: 'TV screenshots',
|
||||
shots: [
|
||||
{ image: tvHomeImage, alt: 'Plezy on TV - home' },
|
||||
{ image: tvLibraryImage, alt: 'Plezy on TV - library' },
|
||||
{ image: tvMdImage, alt: 'Plezy on TV - media details' },
|
||||
{ image: tvPlayerImage, alt: 'Plezy on TV - video player' },
|
||||
],
|
||||
},
|
||||
};
|
||||
];
|
||||
|
||||
let active: DeviceType = $state('phone');
|
||||
let loaded: Record<DeviceType, boolean> = $state({
|
||||
@@ -144,7 +131,7 @@
|
||||
intendedScrollLeft = target;
|
||||
canScrollLeft = target > 10;
|
||||
canScrollRight = target < maxScroll - 10;
|
||||
scrollContainer.scrollTo({ left: target, behavior: 'smooth' });
|
||||
scrollContainer.scrollTo({ left: target });
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
@@ -225,11 +212,10 @@
|
||||
|
||||
<div class="screenshot-panels">
|
||||
{#each devices as device (device.id)}
|
||||
{@const screenshot = screenshots[device.id]}
|
||||
<div
|
||||
id={`screenshots-${device.id}-panel`}
|
||||
role="region"
|
||||
aria-label={screenshot.ariaLabel}
|
||||
aria-label={`${device.label} screenshots`}
|
||||
aria-hidden={active !== device.id}
|
||||
class="screenshot-strip scrollbar-hide content-pad"
|
||||
class:panel-active={active === device.id}
|
||||
@@ -238,15 +224,15 @@
|
||||
}}
|
||||
>
|
||||
{#if loaded[device.id]}
|
||||
{#each screenshot.shots as shot}
|
||||
{#each device.shots as shot}
|
||||
<div class="screenshot-item">
|
||||
<div class={`screenshot-frame ${screenshot.frameClass}`}>
|
||||
<div class={`screenshot-frame ${device.id}-frame`}>
|
||||
<enhanced:img
|
||||
src={shot.image}
|
||||
alt={shot.alt}
|
||||
loading="lazy"
|
||||
class="screenshot-image"
|
||||
sizes={screenshot.sizes}
|
||||
sizes={device.sizes}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -377,6 +363,7 @@
|
||||
width: 100%;
|
||||
gap: 1.25rem;
|
||||
overflow-x: auto;
|
||||
scroll-behavior: smooth;
|
||||
padding-bottom: 1rem;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import Reviews from '$lib/components/Reviews.svelte';
|
||||
import FAQ from '$lib/components/FAQ.svelte';
|
||||
import Footer from '$lib/components/Footer.svelte';
|
||||
import PageMetadata from '$lib/components/PageMetadata.svelte';
|
||||
import { faqSchemaMainEntity } from '$lib/content/faqs';
|
||||
import { buildSoftwareApplicationOffers } from '$lib/content/software_app_offers';
|
||||
|
||||
@@ -13,7 +14,6 @@
|
||||
const title = "Plezy - A Beautiful Plex & Jellyfin Client";
|
||||
const description = "Plezy is a beautiful client for Plex and Jellyfin, available on iOS, Android, Android TV, tvOS, Windows, macOS, and Linux. HDR, Dolby Vision, offline downloads, and more.";
|
||||
const url = "https://plezy.app/";
|
||||
const image = "https://plezy.app/og/plezy-social.png";
|
||||
|
||||
const softwareAppSchema = $derived.by(() => {
|
||||
const schema: Record<string, unknown> = {
|
||||
@@ -50,23 +50,9 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<PageMetadata {title} {description} {url} />
|
||||
|
||||
<svelte:head>
|
||||
<title>{title}</title>
|
||||
<meta name="description" content={description} />
|
||||
<link rel="canonical" href={url} />
|
||||
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="Plezy" />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:url" content={url} />
|
||||
<meta property="og:image" content={image} />
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
<meta name="twitter:image" content={image} />
|
||||
|
||||
{@html `<script type="application/ld+json">${JSON.stringify(softwareAppSchema)}</script>`}
|
||||
{@html `<script type="application/ld+json">${JSON.stringify(faqSchema)}</script>`}
|
||||
</svelte:head>
|
||||
|
||||
@@ -1,28 +1,13 @@
|
||||
<script lang="ts">
|
||||
import Logo from '$lib/components/Logo.svelte';
|
||||
import PageMetadata from '$lib/components/PageMetadata.svelte';
|
||||
|
||||
const title = 'Privacy Policy - Plezy';
|
||||
const description = 'How Plezy stores data on your device and shares data when you use connected services.';
|
||||
const url = 'https://plezy.app/privacy';
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{title}</title>
|
||||
<meta name="description" content={description} />
|
||||
<link rel="canonical" href={url} />
|
||||
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="Plezy" />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:url" content={url} />
|
||||
<meta property="og:image" content="https://plezy.app/og/plezy-social.png" />
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
<meta name="twitter:image" content="https://plezy.app/og/plezy-social.png" />
|
||||
</svelte:head>
|
||||
<PageMetadata {title} {description} {url} />
|
||||
|
||||
<article class="privacy-article">
|
||||
<a href="/" class="back-link">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import Logo from "$lib/components/Logo.svelte";
|
||||
import PageMetadata from "$lib/components/PageMetadata.svelte";
|
||||
import AppleIcon from "~icons/simple-icons/apple";
|
||||
import GooglePlayIcon from "~icons/simple-icons/googleplay";
|
||||
import {
|
||||
@@ -21,24 +22,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Open in Plezy</title>
|
||||
<meta name="description" content="Open this QR code with the Plezy app." />
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
<link rel="canonical" href="https://plezy.app/scan" />
|
||||
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="Plezy" />
|
||||
<meta property="og:title" content="Open in Plezy" />
|
||||
<meta property="og:description" content="Open this QR code with the Plezy app." />
|
||||
<meta property="og:url" content="https://plezy.app/scan" />
|
||||
<meta property="og:image" content="https://plezy.app/og/plezy-social.png" />
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Open in Plezy" />
|
||||
<meta name="twitter:description" content="Open this QR code with the Plezy app." />
|
||||
<meta name="twitter:image" content="https://plezy.app/og/plezy-social.png" />
|
||||
</svelte:head>
|
||||
<PageMetadata title="Open in Plezy" description="Open this QR code with the Plezy app." url="https://plezy.app/scan" noindex />
|
||||
|
||||
<div class="centered-page">
|
||||
<div class="centered-card">
|
||||
|
||||
Reference in New Issue
Block a user