From 9746896a4308f4a62870f1523624b94021f421e8 Mon Sep 17 00:00:00 2001
From: Robert Janus <hallo@robertjanus.de>
Date: Sun, 11 May 2025 14:03:59 +0200
Subject: [PATCH 1/2] add: nuxt-seo-utils basic functions

---
 nuxt.config.ts    |  36 +++++-
 package-lock.json | 284 ++++++++++++++++++++++++++++++++++++++++++++++
 package.json      |   1 +
 3 files changed, 319 insertions(+), 2 deletions(-)

diff --git a/nuxt.config.ts b/nuxt.config.ts
index a2c322d..418b0d8 100755
--- a/nuxt.config.ts
+++ b/nuxt.config.ts
@@ -36,7 +36,7 @@ export default defineNuxtConfig({
     '/privacy': { prerender: true },
   },
 
-  modules: ['@nuxt/icon', '@vueuse/nuxt', '@nuxtjs/device', '@nuxt/fonts'],
+  modules: ['@nuxt/icon', '@vueuse/nuxt', '@nuxtjs/device', '@nuxt/fonts', 'nuxt-seo-utils'],
 
   css : [
     './app/assets/styles/general.css',
@@ -49,5 +49,37 @@ export default defineNuxtConfig({
     './app/assets/styles/form/search.css',
     './app/assets/styles/toolbar.css',
     './app/assets/styles/page.css',
-  ]
+  ],
+
+  site: {
+    url: 'https://pro-papier.de',
+    name: 'ProPapier',
+  },
+
+  seo: {
+    meta: {
+      title: 'ProPapier',
+      description: '"Bezahlt du zuviel fürs Papier? Vergleiche schnell und unkompliziert die Preise für Toiletten-, Küchen- und andere Papier hier."',
+      themeColor: [
+        { content: '#18181b', media: '(prefers-color-scheme: dark)' },
+        { content: 'white', media: '(prefers-color-scheme: light)' },
+      ],
+      twitterCreator: '@webfussel',
+      twitterSite: '@propapier',
+      author: 'webfussel',
+      colorScheme: 'dark light',
+      applicationName: 'ProPapier',
+
+      // Nuxt SEO Utils already sets the below tags for you
+      ogSiteName: 'Propapier',
+      ogLocale: 'de_DE',
+      ogType: 'website',
+      ogUrl: 'https://pro-papier.de',
+      ogTitle: 'ProPapier',
+
+      // Other Nuxt SEO modules handles these
+      ogImage: 'https://example.com/my-og-image.png',
+      robots: 'index, follow',
+    }
+  },
 })
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 7ab19b0..adae26e 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
         "@nuxtjs/device": "^3.2.4",
         "@vueuse/nuxt": "^13.1.0",
         "nuxt": "^3.16.2",
+        "nuxt-seo-utils": "^7.0.11",
         "vue": "latest",
         "vue-router": "latest"
       }
@@ -4173,6 +4174,24 @@
         "url": "https://opencollective.com/typescript-eslint"
       }
     },
+    "node_modules/@unhead/addons": {
+      "version": "2.0.8",
+      "resolved": "https://registry.npmjs.org/@unhead/addons/-/addons-2.0.8.tgz",
+      "integrity": "sha512-FnFBo10ot3flopxgZYUjnJ+r4voZ7/wiPaOod5evShy/3NtC4aIZdma4JLcpt+HtBs9l4zH4SVneYWFrTRXVtg==",
+      "license": "MIT",
+      "dependencies": {
+        "@rollup/pluginutils": "^5.1.4",
+        "estree-walker": "^3.0.3",
+        "magic-string": "^0.30.17",
+        "mlly": "^1.7.4",
+        "ufo": "^1.6.1",
+        "unplugin": "^2.3.2",
+        "unplugin-ast": "^0.14.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/harlan-zw"
+      }
+    },
     "node_modules/@unhead/vue": {
       "version": "2.0.8",
       "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-2.0.8.tgz",
@@ -7623,6 +7642,18 @@
       "integrity": "sha512-K6acvFaelNxx8wc2VjbIzXKDVB0Khs0QT35U6NkGfTdCmjLNcO2945m7RFNR9/RPVFm48hq7QPzK8uGH18HCGw==",
       "license": "MIT"
     },
+    "node_modules/image-size": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/image-size/-/image-size-2.0.2.tgz",
+      "integrity": "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==",
+      "license": "MIT",
+      "bin": {
+        "image-size": "bin/image-size.js"
+      },
+      "engines": {
+        "node": ">=16.x"
+      }
+    },
     "node_modules/impound": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/impound/-/impound-0.2.2.tgz",
@@ -9130,6 +9161,211 @@
         }
       }
     },
+    "node_modules/nuxt-seo-utils": {
+      "version": "7.0.11",
+      "resolved": "https://registry.npmjs.org/nuxt-seo-utils/-/nuxt-seo-utils-7.0.11.tgz",
+      "integrity": "sha512-uqk9vcsbwRCoaV/fnBr9x26rQ2kA6xI08VIWLluqRvgBsexExu0ADTP1kQ/mNGePCf9GNQKQo/8fksg9dKGAAA==",
+      "license": "MIT",
+      "dependencies": {
+        "@nuxt/kit": "^3.17.1",
+        "@unhead/addons": "^2.0.8",
+        "defu": "^6.1.4",
+        "escape-string-regexp": "^5.0.0",
+        "fast-glob": "^3.3.3",
+        "image-size": "^2.0.2",
+        "nuxt-site-config": "^3.1.9",
+        "pathe": "^2.0.3",
+        "pkg-types": "^2.1.0",
+        "scule": "^1.3.0",
+        "semver": "^7.7.1",
+        "ufo": "^1.6.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/harlan-zw"
+      }
+    },
+    "node_modules/nuxt-seo-utils/node_modules/@nuxt/kit": {
+      "version": "3.17.2",
+      "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.17.2.tgz",
+      "integrity": "sha512-Mz2Ni8iUwty5LBs3LepUL43rI2xXbuAz3Cqq37L9frOD2QI2tQUtasYaSoKk6U7nvYzuW2z/2b3YOLkMNi/k2w==",
+      "license": "MIT",
+      "dependencies": {
+        "c12": "^3.0.3",
+        "consola": "^3.4.2",
+        "defu": "^6.1.4",
+        "destr": "^2.0.5",
+        "errx": "^0.1.0",
+        "exsolve": "^1.0.5",
+        "ignore": "^7.0.4",
+        "jiti": "^2.4.2",
+        "klona": "^2.0.6",
+        "knitwork": "^1.2.0",
+        "mlly": "^1.7.4",
+        "ohash": "^2.0.11",
+        "pathe": "^2.0.3",
+        "pkg-types": "^2.1.0",
+        "scule": "^1.3.0",
+        "semver": "^7.7.1",
+        "std-env": "^3.9.0",
+        "tinyglobby": "^0.2.13",
+        "ufo": "^1.6.1",
+        "unctx": "^2.4.1",
+        "unimport": "^5.0.1",
+        "untyped": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      }
+    },
+    "node_modules/nuxt-seo-utils/node_modules/confbox": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz",
+      "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
+      "license": "MIT"
+    },
+    "node_modules/nuxt-seo-utils/node_modules/local-pkg": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.1.tgz",
+      "integrity": "sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==",
+      "license": "MIT",
+      "dependencies": {
+        "mlly": "^1.7.4",
+        "pkg-types": "^2.0.1",
+        "quansync": "^0.2.8"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/antfu"
+      }
+    },
+    "node_modules/nuxt-seo-utils/node_modules/ohash": {
+      "version": "2.0.11",
+      "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz",
+      "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
+      "license": "MIT"
+    },
+    "node_modules/nuxt-seo-utils/node_modules/pkg-types": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz",
+      "integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==",
+      "license": "MIT",
+      "dependencies": {
+        "confbox": "^0.2.1",
+        "exsolve": "^1.0.1",
+        "pathe": "^2.0.3"
+      }
+    },
+    "node_modules/nuxt-seo-utils/node_modules/tinyglobby": {
+      "version": "0.2.13",
+      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz",
+      "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
+      "license": "MIT",
+      "dependencies": {
+        "fdir": "^6.4.4",
+        "picomatch": "^4.0.2"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/SuperchupuDev"
+      }
+    },
+    "node_modules/nuxt-seo-utils/node_modules/unimport": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/unimport/-/unimport-5.0.1.tgz",
+      "integrity": "sha512-1YWzPj6wYhtwHE+9LxRlyqP4DiRrhGfJxdtH475im8ktyZXO3jHj/3PZ97zDdvkYoovFdi0K4SKl3a7l92v3sQ==",
+      "license": "MIT",
+      "dependencies": {
+        "acorn": "^8.14.1",
+        "escape-string-regexp": "^5.0.0",
+        "estree-walker": "^3.0.3",
+        "local-pkg": "^1.1.1",
+        "magic-string": "^0.30.17",
+        "mlly": "^1.7.4",
+        "pathe": "^2.0.3",
+        "picomatch": "^4.0.2",
+        "pkg-types": "^2.1.0",
+        "scule": "^1.3.0",
+        "strip-literal": "^3.0.0",
+        "tinyglobby": "^0.2.13",
+        "unplugin": "^2.3.2",
+        "unplugin-utils": "^0.2.4"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      }
+    },
+    "node_modules/nuxt-site-config": {
+      "version": "3.1.9",
+      "resolved": "https://registry.npmjs.org/nuxt-site-config/-/nuxt-site-config-3.1.9.tgz",
+      "integrity": "sha512-YB69GX0st8drv1d5xypweseiEWeR22tfGdyVH3U4R+mpUSz8paBx48ArKC6MgV22DKItoQm51LVoapF5pl5bEQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@nuxt/kit": "^3.16.2",
+        "nuxt-site-config-kit": "3.1.9",
+        "pathe": "^2.0.3",
+        "pkg-types": "^2.1.0",
+        "sirv": "^3.0.1",
+        "site-config-stack": "3.1.9",
+        "ufo": "^1.5.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/harlan-zw"
+      }
+    },
+    "node_modules/nuxt-site-config-kit": {
+      "version": "3.1.9",
+      "resolved": "https://registry.npmjs.org/nuxt-site-config-kit/-/nuxt-site-config-kit-3.1.9.tgz",
+      "integrity": "sha512-bcmpajYJgkNzA0jTq6CmmhKF2wHZUUKeVx/CIGI8lwWuAD81EBUZN0T4iKvVDo54g9UBrUUl8/5GhD65YBBG0A==",
+      "license": "MIT",
+      "dependencies": {
+        "@nuxt/kit": "^3.16.2",
+        "pkg-types": "^2.1.0",
+        "site-config-stack": "3.1.9",
+        "std-env": "^3.9.0",
+        "ufo": "^1.5.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/harlan-zw"
+      }
+    },
+    "node_modules/nuxt-site-config-kit/node_modules/confbox": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz",
+      "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
+      "license": "MIT"
+    },
+    "node_modules/nuxt-site-config-kit/node_modules/pkg-types": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz",
+      "integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==",
+      "license": "MIT",
+      "dependencies": {
+        "confbox": "^0.2.1",
+        "exsolve": "^1.0.1",
+        "pathe": "^2.0.3"
+      }
+    },
+    "node_modules/nuxt-site-config/node_modules/confbox": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz",
+      "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
+      "license": "MIT"
+    },
+    "node_modules/nuxt-site-config/node_modules/pkg-types": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz",
+      "integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==",
+      "license": "MIT",
+      "dependencies": {
+        "confbox": "^0.2.1",
+        "exsolve": "^1.0.1",
+        "pathe": "^2.0.3"
+      }
+    },
     "node_modules/nuxt/node_modules/confbox": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz",
@@ -10978,6 +11214,21 @@
       "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
       "license": "MIT"
     },
+    "node_modules/site-config-stack": {
+      "version": "3.1.9",
+      "resolved": "https://registry.npmjs.org/site-config-stack/-/site-config-stack-3.1.9.tgz",
+      "integrity": "sha512-ed53+wLi+36SGqidU+YUpl7f1OHClPLmvUJ/aYZny1dCBnXvOsuFottrMkXDIK2N5UaMED9mz8KrRZTk94ARCg==",
+      "license": "MIT",
+      "dependencies": {
+        "ufo": "^1.5.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/harlan-zw"
+      },
+      "peerDependencies": {
+        "vue": "^3"
+      }
+    },
     "node_modules/slash": {
       "version": "5.1.0",
       "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
@@ -11859,6 +12110,39 @@
         "node": ">=18.12.0"
       }
     },
+    "node_modules/unplugin-ast": {
+      "version": "0.14.6",
+      "resolved": "https://registry.npmjs.org/unplugin-ast/-/unplugin-ast-0.14.6.tgz",
+      "integrity": "sha512-HdntpxAN8fWyJ28n8iRkRrez9UrxTPda27XzdEkI8tz0Cn0+fLrnN+8qHqHlzRWXxSPVP7M9eEJ5MeMwbbhy4g==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/generator": "^7.27.0",
+        "ast-kit": "^1.4.2",
+        "magic-string-ast": "^0.9.1",
+        "unplugin": "^2.3.2"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sxzz"
+      }
+    },
+    "node_modules/unplugin-ast/node_modules/magic-string-ast": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-0.9.1.tgz",
+      "integrity": "sha512-18dv2ZlSSgJ/jDWlZGKfnDJx56ilNlYq9F7NnwuWTErsmYmqJ2TWE4l1o2zlUHBYUGBy3tIhPCC1gxq8M5HkMA==",
+      "license": "MIT",
+      "dependencies": {
+        "magic-string": "^0.30.17"
+      },
+      "engines": {
+        "node": ">=20.18.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sxzz"
+      }
+    },
     "node_modules/unplugin-utils": {
       "version": "0.2.4",
       "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.2.4.tgz",
diff --git a/package.json b/package.json
index 9ea8575..eb030f4 100755
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
     "@nuxtjs/device": "^3.2.4",
     "@vueuse/nuxt": "^13.1.0",
     "nuxt": "^3.16.2",
+    "nuxt-seo-utils": "^7.0.11",
     "vue": "latest",
     "vue-router": "latest"
   }

From 33713419f6d21c9c8b92cf11b2904138d58ecab8 Mon Sep 17 00:00:00 2001
From: Robert Janus <hallo@robertjanus.de>
Date: Sun, 11 May 2025 14:05:01 +0200
Subject: [PATCH 2/2] fix: (seo-)headings for pages + css

---
 app/assets/styles/general.css | 5 +----
 app/assets/styles/page.css    | 8 ++++++++
 app/components/Pp/Header.vue  | 4 +++-
 app/pages/imprint.vue         | 1 +
 app/pages/index.vue           | 3 +++
 app/pages/privacy.vue         | 4 ++--
 6 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/app/assets/styles/general.css b/app/assets/styles/general.css
index 99b3170..da0985a 100755
--- a/app/assets/styles/general.css
+++ b/app/assets/styles/general.css
@@ -1,6 +1,7 @@
 :root {
   --padding-default: 1rem;
   --padding-small: 0.5rem;
+  --padding-large: 2rem;
   --radius-default: 3px;
   --transition-default: 150ms;
 
@@ -205,8 +206,4 @@ dialog {
   &::backdrop {
     background: rgba(0, 0, 0, 0.5);
   }
-}
-
-.Legal {
-  padding: var(--padding-default);
 }
\ No newline at end of file
diff --git a/app/assets/styles/page.css b/app/assets/styles/page.css
index 24ab7a9..fe9b098 100644
--- a/app/assets/styles/page.css
+++ b/app/assets/styles/page.css
@@ -53,6 +53,10 @@
     height: 100%;
 }
 
+.content-text {
+    padding: var(--padding-large) var(--padding-default) var(--padding-default);
+}
+
 .info-text {
     padding: 0 var(--padding-default);
     text-align: center;
@@ -60,4 +64,8 @@
     top: 40%;
     transform: translateY(-50%);
     position: absolute;
+}
+
+.Legal {
+    padding: var(--padding-large) var(--padding-default);
 }
\ No newline at end of file
diff --git a/app/components/Pp/Header.vue b/app/components/Pp/Header.vue
index 1c88ae1..a6befae 100755
--- a/app/components/Pp/Header.vue
+++ b/app/components/Pp/Header.vue
@@ -1,6 +1,8 @@
 <template>
   <div class="Header">
-    <img class="logo" src="/img/propapier.svg" alt="ProPapier logo" />
+    <NuxtLink class="header-text" to="/">
+      <img class="logo" src="/img/propapier.svg" alt="ProPapier logo" />
+    </NuxtLink>
     <div>
       <header class="roboto-condensed">
         <NuxtLink class="header-text" to="/">
diff --git a/app/pages/imprint.vue b/app/pages/imprint.vue
index 800e9f6..2060e07 100644
--- a/app/pages/imprint.vue
+++ b/app/pages/imprint.vue
@@ -1,6 +1,7 @@
 <template>
   <div>
     <section class="Legal flex-col gap-default content full">
+      <h1>Impressum</h1>
       <div>
         <p>
           Fiona Lena Urban<br/>
diff --git a/app/pages/index.vue b/app/pages/index.vue
index 9019be1..aa4f606 100755
--- a/app/pages/index.vue
+++ b/app/pages/index.vue
@@ -18,6 +18,9 @@
         </div>
       </Teleport>
       <section class="content flex-col">
+        <div class="content-text">
+          <h1>Mit ProPapier Preise vergleichen und sparen</h1>
+        </div>
         <aside class="filter-bar">
           <button v-for="(button, index) in filterButtons" @click="() => sort(index)" :class="{ 'active': button.active }">
             {{ button.label }}
diff --git a/app/pages/privacy.vue b/app/pages/privacy.vue
index d15e439..d395b3e 100644
--- a/app/pages/privacy.vue
+++ b/app/pages/privacy.vue
@@ -1,8 +1,8 @@
 <template>
   <section class="Legal flex-col gap-default content full">
-    <h3>
+    <h1>
       Datenschutzerklärung
-    </h3>
+    </h1>
     <p>
       Wir senden keinerlei Daten an Drittanbieter.
     </p>