From 9642496e5ac696edab08e980eadffccf7ac77566 Mon Sep 17 00:00:00 2001
From: webfussel
Date: Wed, 12 Feb 2025 13:18:55 +0100
Subject: [PATCH] FIX: mpa, nuxt4 future, improvements in intro and services
Added mpa support, nuxt4 future compatibility, improvements in intro and services
---
app.vue => app/app.vue | 12 +++
app/assets/css/button.css | 75 +++++++++++++++++
{assets => app/assets}/css/customers.css | 0
{assets => app/assets}/css/fonts.css | 0
{assets => app/assets}/css/footer.css | 0
{assets => app/assets}/css/global.css | 41 +++++++++
{assets => app/assets}/css/header.css | 21 ++---
{assets => app/assets}/css/intro.css | 0
{assets => app/assets}/css/person.css | 0
{assets => app/assets}/css/services.css | 0
{assets => app/assets}/css/skills.css | 0
app/assets/css/technology.css | 16 ++++
{components => app/components}/Button.vue | 10 +--
{components => app/components}/Customers.vue | 2 +-
app/components/Footer.vue | 84 +++++++++++++++++++
{components => app/components}/Header.vue | 55 ++++--------
{components => app/components}/Intro.vue | 14 +++-
{components => app/components}/Person.vue | 4 +-
{components => app/components}/Services.vue | 10 ++-
{components => app/components}/Skills.vue | 13 ++-
{components => app/components}/Technology.vue | 2 +-
{layouts => app/layouts}/default.vue | 0
pages/[...route].vue => app/pages/contact.vue | 0
{pages => app/pages}/imp.vue | 0
app/pages/index.vue | 6 ++
app/pages/references.vue | 5 ++
app/pages/services.vue | 5 ++
{utils => app/utils}/image.ts | 0
Skills.ts => app/utils/skills.ts | 2 +-
assets/css/button.css | 24 ------
assets/css/technology.css | 32 -------
components/Footer.vue | 44 ----------
nuxt.config.ts | 7 ++
package-lock.json | 11 +++
package.json | 1 +
35 files changed, 324 insertions(+), 172 deletions(-)
rename app.vue => app/app.vue (85%)
create mode 100644 app/assets/css/button.css
rename {assets => app/assets}/css/customers.css (100%)
rename {assets => app/assets}/css/fonts.css (100%)
rename {assets => app/assets}/css/footer.css (100%)
rename {assets => app/assets}/css/global.css (83%)
rename {assets => app/assets}/css/header.css (93%)
rename {assets => app/assets}/css/intro.css (100%)
rename {assets => app/assets}/css/person.css (100%)
rename {assets => app/assets}/css/services.css (100%)
rename {assets => app/assets}/css/skills.css (100%)
create mode 100644 app/assets/css/technology.css
rename {components => app/components}/Button.vue (69%)
rename {components => app/components}/Customers.vue (98%)
create mode 100644 app/components/Footer.vue
rename {components => app/components}/Header.vue (70%)
rename {components => app/components}/Intro.vue (63%)
rename {components => app/components}/Person.vue (87%)
rename {components => app/components}/Services.vue (92%)
rename {components => app/components}/Skills.vue (84%)
rename {components => app/components}/Technology.vue (92%)
rename {layouts => app/layouts}/default.vue (100%)
rename pages/[...route].vue => app/pages/contact.vue (100%)
rename {pages => app/pages}/imp.vue (100%)
create mode 100644 app/pages/index.vue
create mode 100644 app/pages/references.vue
create mode 100644 app/pages/services.vue
rename {utils => app/utils}/image.ts (100%)
rename Skills.ts => app/utils/skills.ts (100%)
delete mode 100644 assets/css/button.css
delete mode 100644 assets/css/technology.css
delete mode 100644 components/Footer.vue
diff --git a/app.vue b/app/app.vue
similarity index 85%
rename from app.vue
rename to app/app.vue
index 8847d80..4d40d81 100644
--- a/app.vue
+++ b/app/app.vue
@@ -25,3 +25,15 @@ useSeoMeta({
twitterUrl: 'https://webfussel.de',
})
+
+
diff --git a/app/assets/css/button.css b/app/assets/css/button.css
new file mode 100644
index 0000000..7fc1733
--- /dev/null
+++ b/app/assets/css/button.css
@@ -0,0 +1,75 @@
+.Button {
+ all: unset;
+ transition: 250ms;
+ cursor: pointer;
+ padding: 1rem 1.5rem;
+ outline: 3px solid transparent;
+ box-shadow: 0 0 0 0 var(--color-orange);
+ border-radius: 99999px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 1rem;
+
+ &.default {
+ background: var(--color-orange);
+ color: var(--color-black);
+ }
+
+ &.white {
+ background: var(--color-white);
+ color: var(--color-black);
+ }
+
+ &:hover {
+ outline-color: var(--color-black);
+ box-shadow: 0 0 0 6px var(--color-orange);
+ }
+
+ &.cta {
+ font-size: clamp(1rem, 2vw, 1.5rem);
+ }
+}
+
+.DualButton {
+ --size: 2.2rem;
+ display: flex;
+ width: 100%;
+
+ & .divider {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: var(--color-black);
+ color: var(--color-white);
+ border-radius: 9999px;
+ width: var(--size);
+ height: var(--size);
+ padding: var(--size);
+ font-size: 1.2rem;
+ z-index: 1;
+ margin-left: calc(var(--size) * -1 - 25px);
+ border: 2px solid var(--color-black);
+ }
+
+ .Button {
+ border: 2px solid currentColor;
+ }
+
+ & .Button:hover {
+ outline: none;
+ box-shadow: none;
+ background-color: var(--color-black);
+ color: var(--color-white);
+ border-color: var(--color-orange);
+ }
+
+ & .Button:first-child {
+ padding-right: calc(var(--size) * 2);
+ }
+
+ & .Button:last-child {
+ padding-left: calc(var(--size) * 2);
+ margin-left: calc(var(--size) * -1 - 25px);
+ }
+}
\ No newline at end of file
diff --git a/assets/css/customers.css b/app/assets/css/customers.css
similarity index 100%
rename from assets/css/customers.css
rename to app/assets/css/customers.css
diff --git a/assets/css/fonts.css b/app/assets/css/fonts.css
similarity index 100%
rename from assets/css/fonts.css
rename to app/assets/css/fonts.css
diff --git a/assets/css/footer.css b/app/assets/css/footer.css
similarity index 100%
rename from assets/css/footer.css
rename to app/assets/css/footer.css
diff --git a/assets/css/global.css b/app/assets/css/global.css
similarity index 83%
rename from assets/css/global.css
rename to app/assets/css/global.css
index 82402e2..243a345 100644
--- a/assets/css/global.css
+++ b/app/assets/css/global.css
@@ -73,6 +73,7 @@ body {
background: var(--color-black);
}
+.h1, .h2, .h3, .h4, .h5, .h6,
h1, h2, h3, h4, h5, h6 {
text-align: left;
font-family: 'Roboto Condensed', sans-serif;
@@ -82,8 +83,11 @@ h1 {
font-size: 4rem;
}
+.h2,
+h2,
h3 {
font-size: 1.5rem;
+ font-weight: bold;
}
a {
@@ -198,6 +202,43 @@ span.chip {
box-shadow: 0 19px 38px rgba(0, 0, 0, 0.30), 0 15px 12px rgba(0, 0, 0, 0.22);
}
+.tip-container {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.tip-container .tip {
+ scale: 0;
+ position: absolute;
+ top: -3rem;
+ width: max-content;
+ border: 1px solid var(--color-white);
+ border-radius: 999px;
+ background-color: var(--color-black);
+ padding: .5em 1.5rem;
+ transition: 150ms;
+}
+
+.tip-container:hover .tip {
+ scale: 1;
+}
+
+.animate-up-down {
+ animation: up-down 1.5s ease-in-out alternate-reverse infinite;
+}
+
+@keyframes up-down {
+ 0% {
+ translate: 0 -0.1rem;
+ }
+
+ 100% {
+ translate: 0 0.4em;
+ }
+}
+
@media (width <= 780px) {
h1, h2, h3, h4, h5, h6, p {
text-align: center;
diff --git a/assets/css/header.css b/app/assets/css/header.css
similarity index 93%
rename from assets/css/header.css
rename to app/assets/css/header.css
index b69e92e..9c98e86 100644
--- a/assets/css/header.css
+++ b/app/assets/css/header.css
@@ -10,10 +10,6 @@
position: fixed;
z-index: 1000;
- & .socials {
- gap: 1rem;
- }
-
& .logo {
fill-rule: evenodd;
clip-rule: evenodd;
@@ -51,19 +47,23 @@
}
& nav {
- flex: 3;
position: relative;
font-weight: normal;
font-size: 1.2rem;
display: flex;
justify-content: space-between;
align-items: center;
+
+ & .active {
+ color: var(--color-orange);
+ }
}
& > .wrapper {
display: flex;
align-items: center;
- padding: 15px 30px;
+ justify-content: space-between;
+ padding: 15px 22px;
transition: 750ms;
backdrop-filter: blur(10px);
border-radius: 0;
@@ -174,13 +174,6 @@
color: var(--color-white);
flex-direction: column;
- & .socials {
- flex-direction: row;
- height: max-content;
- gap: 3rem;
- padding-bottom: 2rem;
- }
-
& ul {
flex-direction: column;
justify-content: center;
@@ -188,7 +181,7 @@
gap: 8vh;
& li {
- font-size: 10vw;
+ font-size: clamp(1rem, 10vw, 3rem);
}
}
}
diff --git a/assets/css/intro.css b/app/assets/css/intro.css
similarity index 100%
rename from assets/css/intro.css
rename to app/assets/css/intro.css
diff --git a/assets/css/person.css b/app/assets/css/person.css
similarity index 100%
rename from assets/css/person.css
rename to app/assets/css/person.css
diff --git a/assets/css/services.css b/app/assets/css/services.css
similarity index 100%
rename from assets/css/services.css
rename to app/assets/css/services.css
diff --git a/assets/css/skills.css b/app/assets/css/skills.css
similarity index 100%
rename from assets/css/skills.css
rename to app/assets/css/skills.css
diff --git a/app/assets/css/technology.css b/app/assets/css/technology.css
new file mode 100644
index 0000000..2e2d0b1
--- /dev/null
+++ b/app/assets/css/technology.css
@@ -0,0 +1,16 @@
+.Technology {
+ position: relative;
+ align-items: center;
+
+ &.s img {
+ height: 15px;
+ }
+
+ &.m img {
+ height: 30px;
+ }
+
+ &.l img {
+ height: 50px;
+ }
+}
diff --git a/components/Button.vue b/app/components/Button.vue
similarity index 69%
rename from components/Button.vue
rename to app/components/Button.vue
index a5f93d7..8c9095d 100644
--- a/components/Button.vue
+++ b/app/components/Button.vue
@@ -1,6 +1,6 @@
-
- {{ label }}
+
+
@@ -9,13 +9,13 @@
type Props = {
type ?: 'a' | 'button'
href ?: string
- label : string
+ design ?: string
}
const {
type = 'a',
- href,
- label,
+ href = '#',
+ design = 'default',
} = defineProps()
const actualProps = () => {
diff --git a/components/Customers.vue b/app/components/Customers.vue
similarity index 98%
rename from components/Customers.vue
rename to app/components/Customers.vue
index e9ed5b3..a16dcdf 100644
--- a/components/Customers.vue
+++ b/app/components/Customers.vue
@@ -38,7 +38,7 @@
diff --git a/components/Header.vue b/app/components/Header.vue
similarity index 70%
rename from components/Header.vue
rename to app/components/Header.vue
index 889621e..c8b221c 100644
--- a/components/Header.vue
+++ b/app/components/Header.vue
@@ -28,15 +28,8 @@
-
@@ -57,47 +50,31 @@ const burgerLabel = computed(() => isBurgerOpen.value ? burgerCloseLabel : burge
const nav = [
{
- to: `/#intro`,
- label: 'Über mich',
- 'aria-label': 'Link dieser Seite: Über mich'
- }, {
- to: `/#customers`,
- label: 'Kunden',
- 'aria-label': 'Link dieser Seite: Kunden'
- }, {
- to: `/#services`,
- label: 'Services',
- 'aria-label': 'Link dieser Seite: Services'
- }
-]
-
-const socials = [
- {
- href: 'https://www.linkedin.com/in/webfussel/',
- icon: 'ri:linkedin-box-line',
- 'aria-label': 'Externer Link: LinkedIn Profil'
+ to: `/`,
+ label: 'home',
+ 'aria-label': 'Link dieser Seite: Startseite'
},
{
- href: 'https://mastodontech.de/@webfussel',
- icon: 'ri:mastodon-line',
- rel: 'me',
- 'aria-label': 'Externer Link: Mastodon Profil'
+ to: `/services`,
+ label: 'leistungen',
+ aria: 'Link dieser Seite: Leistungen'
},
{
- href: 'https://bsky.app/profile/webfussel.de',
- icon: 'ri:bluesky-line',
- 'aria-label': 'Externer Link: Bluesky Profil'
+ to: `/references`,
+ label: 'referenzen',
+ aria: 'Link dieser Seite: Referenzen'
},
{
- href: 'https://ko-fi.com/webfussel',
- icon: 'wf:kofi',
- 'aria-label': 'Externer Link: KoFi Profil'
+ to: `/contact`,
+ label: 'kontakt',
+ aria: 'Link dieser Seite: Kontakt'
},
]
onMounted(() => {
observer = new IntersectionObserver(([entry]) => {
- const {isIntersecting} = entry
+ if (!entry) return
+ const { isIntersecting } = entry
header.value?.classList.toggle('sticks', !isIntersecting)
headerWrapper.value?.classList.toggle('z-4', !isIntersecting)
headerWrapper.value?.classList.toggle('z-0', isIntersecting)
diff --git a/components/Intro.vue b/app/components/Intro.vue
similarity index 63%
rename from components/Intro.vue
rename to app/components/Intro.vue
index 9c3b240..52d3364 100644
--- a/components/Intro.vue
+++ b/app/components/Intro.vue
@@ -9,17 +9,21 @@
Component & API Entwicklerin
- Ich unterstütze Unternehmen dabei, ihre Daten so richtig nice zusammen zu sammeln
- und in wunderschöne Komponenten zu gießen.
+ Ich unterstütze Unternehmen dabei, ihre Daten von verschiedenen Endpunkten sauber aufzubereiten
+ und anschließend in einer Webapplication schön zu verpacken.
Mit über 20 Jahren Erfahrung in der Webentwicklung habe ich
inzwischen so ziemlich jeden Stuff miterlebt.
- Du brauchst großartige Komponenten und saubere Schnittstellen?
+ Egal, ob Komponenten, Schnittstellen oder Anbindung an Headless CMS.
+ Ich biete dir genau das, was du brauchst, um eine individuelle WebApp in Fahrt zu bringen, deren Inhalte einfach zu verändern sind.
-
+
+
+ Fussel erklärt's dir
+
+
\ No newline at end of file
diff --git a/components/Person.vue b/app/components/Person.vue
similarity index 87%
rename from components/Person.vue
rename to app/components/Person.vue
index f40dba3..5fbb0b9 100644
--- a/components/Person.vue
+++ b/app/components/Person.vue
@@ -13,7 +13,9 @@
{{tag}}
{{flavour}}
-
+
+ Zur Homepage
+
diff --git a/components/Services.vue b/app/components/Services.vue
similarity index 92%
rename from components/Services.vue
rename to app/components/Services.vue
index eb433a4..d27fdb6 100644
--- a/components/Services.vue
+++ b/app/components/Services.vue
@@ -12,10 +12,13 @@
{{service.availability}}
{{service.smallClaim}}
-
+
+ {{ service.button }}
+
+
@@ -59,6 +62,7 @@ const services = [
price: '149 € / Einmalig',
availability: 'Frei',
smallClaim: 'Du hast eine Homepage und willst mal drüber schauen lassen?',
+ icon: 'magnifying-glass',
button: 'Jetzt untersuchen',
link: 'https://tidycal.com/webfussel/quick-check',
list: [
@@ -73,6 +77,7 @@ const services = [
price: 'ab 999 € je nach Umfang',
availability: slotsLabel,
smallClaim: 'Umsetzung deiner Vision. Von einzelnen Tickets bis hin zu kompletten Anwendungen.',
+ icon: 'trend-up',
button: 'Jetzt durchstarten',
link: 'https://tidycal.com/webfussel/project-booking',
list: [
@@ -86,6 +91,7 @@ const services = [
availability: `Frei ab ${readableDate}`,
price: '105 € / Stunde',
smallClaim: 'Du brauchst einfach Unterstützung im Team, bis sich der Trubel legt?',
+ icon: 'timer',
button: 'Jetzt buchen',
link: 'https://tidycal.com/webfussel/hourly-booking',
list: [
diff --git a/components/Skills.vue b/app/components/Skills.vue
similarity index 84%
rename from components/Skills.vue
rename to app/components/Skills.vue
index 70ed0d0..6fb234f 100644
--- a/components/Skills.vue
+++ b/app/components/Skills.vue
@@ -20,17 +20,22 @@
-
Du brauchst was davon? Kein Ding.
-
+ Manche von euch haben hier sicher kein Wort verstanden.
+
+
+
+
+ Für normale Menschen
+
diff --git a/nuxt.config.ts b/nuxt.config.ts
index 434d31a..84558c4 100644
--- a/nuxt.config.ts
+++ b/nuxt.config.ts
@@ -1,5 +1,8 @@
export default defineNuxtConfig({
ssr: true,
+ future: {
+ compatibilityVersion: 4,
+ },
nitro: {
prerender: {
@@ -36,6 +39,10 @@ export default defineNuxtConfig({
},
app: {
+ pageTransition: {
+ name: 'page',
+ mode: 'out-in',
+ },
head: {
htmlAttrs: { lang: 'de' },
link: [
diff --git a/package-lock.json b/package-lock.json
index d48f081..3b3765a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,6 +7,7 @@
"name": "nuxt-app",
"hasInstallScript": true,
"devDependencies": {
+ "@iconify-json/material-symbols": "^1.2.14",
"@iconify-json/ri": "^1.2.5",
"@nuxt/icon": "^1.10.3",
"nuxt": "^3.15.3",
@@ -1037,6 +1038,16 @@
"node": ">=18"
}
},
+ "node_modules/@iconify-json/material-symbols": {
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@iconify-json/material-symbols/-/material-symbols-1.2.14.tgz",
+ "integrity": "sha512-S0AAFFQPVr8Dkrprspz/otNjxdD3rJRXDGZjbO8a8zn8ZR5mO8jAF81lVoTfUWxPH6SCtH2lK1JQGXHGPxld7g==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@iconify/types": "*"
+ }
+ },
"node_modules/@iconify-json/ri": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/@iconify-json/ri/-/ri-1.2.5.tgz",
diff --git a/package.json b/package.json
index 545325d..aa10823 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"build:deploy": "nuxt build && firebase deploy --only hosting"
},
"devDependencies": {
+ "@iconify-json/material-symbols": "^1.2.14",
"@iconify-json/ri": "^1.2.5",
"@nuxt/icon": "^1.10.3",
"nuxt": "^3.15.3",