Fix styling of landing page
This commit is contained in:
79
src/App.vue
79
src/App.vue
@@ -1,14 +1,25 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RouterLink, RouterView } from 'vue-router'
|
import { RouterLink, RouterView } from 'vue-router'
|
||||||
import WelcomeText from './components/WelcomeText.vue'
|
import ThemeToggle from './components/ThemeToggle.vue'
|
||||||
|
import LogoSvg from './components/icons/IconLogo.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<ThemeToggle />
|
||||||
<header>
|
<header>
|
||||||
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
|
|
||||||
|
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<WelcomeText msg="Livonsaaren Tietokonepaja" />
|
<div class="title-section">
|
||||||
|
<div class="greetings">
|
||||||
|
<div class="title-with-logo">
|
||||||
|
<LogoSvg alt="Tietokonepajan logo" class="logo" />
|
||||||
|
<h1>Livonsaaren Tietokonepaja</h1>
|
||||||
|
</div>
|
||||||
|
<h3>
|
||||||
|
Tervetuloa Livonsaaren Tietokonepajan verkkosivuille! Tarjoamme kattavia IT-palveluita,
|
||||||
|
laitehuoltoja, kotisivuratkaisuja ja Linux-tukea. Tutustu palveluihimme ja ota yhteyttä!
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
<RouterLink to="/">Etusivu</RouterLink>
|
<RouterLink to="/">Etusivu</RouterLink>
|
||||||
@@ -26,9 +37,44 @@ header {
|
|||||||
max-height: 100vh;
|
max-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1.5rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-with-logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
display: block;
|
height: 100%;
|
||||||
margin: 0 auto 2rem;
|
width: auto;
|
||||||
|
max-height: 120px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.greetings h1 {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 2.6rem;
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.greetings h3 {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.greetings h1,
|
||||||
|
.greetings h3 {
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
@@ -63,8 +109,27 @@ nav a:first-of-type {
|
|||||||
padding-right: calc(var(--section-gap) / 2);
|
padding-right: calc(var(--section-gap) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title-section {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-with-logo {
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
margin: 0 2rem 0 0;
|
height: 100%;
|
||||||
|
width: auto;
|
||||||
|
max-height: 100px;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.greetings h1,
|
||||||
|
.greetings h3 {
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
header .wrapper {
|
header .wrapper {
|
||||||
|
|||||||
@@ -33,11 +33,50 @@
|
|||||||
--color-heading: var(--vt-c-text-light-1);
|
--color-heading: var(--vt-c-text-light-1);
|
||||||
--color-text: var(--vt-c-text-light-1);
|
--color-text: var(--vt-c-text-light-1);
|
||||||
|
|
||||||
|
/* SVG/Icon colors */
|
||||||
|
--color-svg-fill: #000000;
|
||||||
|
--color-svg-stroke: #000000;
|
||||||
|
|
||||||
--section-gap: 160px;
|
--section-gap: 160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dark theme - manual toggle */
|
||||||
|
html.dark {
|
||||||
|
--color-background: var(--vt-c-black);
|
||||||
|
--color-background-soft: var(--vt-c-black-soft);
|
||||||
|
--color-background-mute: var(--vt-c-black-mute);
|
||||||
|
|
||||||
|
--color-border: var(--vt-c-divider-dark-2);
|
||||||
|
--color-border-hover: var(--vt-c-divider-dark-1);
|
||||||
|
|
||||||
|
--color-heading: var(--vt-c-text-dark-1);
|
||||||
|
--color-text: var(--vt-c-text-dark-2);
|
||||||
|
|
||||||
|
/* SVG/Icon colors for dark theme */
|
||||||
|
--color-svg-fill: #ffffff;
|
||||||
|
--color-svg-stroke: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Light theme - manual toggle */
|
||||||
|
html.light {
|
||||||
|
--color-background: var(--vt-c-white);
|
||||||
|
--color-background-soft: var(--vt-c-white-soft);
|
||||||
|
--color-background-mute: var(--vt-c-white-mute);
|
||||||
|
|
||||||
|
--color-border: var(--vt-c-divider-light-2);
|
||||||
|
--color-border-hover: var(--vt-c-divider-light-1);
|
||||||
|
|
||||||
|
--color-heading: var(--vt-c-text-light-1);
|
||||||
|
--color-text: var(--vt-c-text-light-1);
|
||||||
|
|
||||||
|
/* SVG/Icon colors for light theme */
|
||||||
|
--color-svg-fill: #000000;
|
||||||
|
--color-svg-stroke: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* System preference fallback - only when no manual preference is set */
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
:root {
|
html:not(.light):not(.dark) {
|
||||||
--color-background: var(--vt-c-black);
|
--color-background: var(--vt-c-black);
|
||||||
--color-background-soft: var(--vt-c-black-soft);
|
--color-background-soft: var(--vt-c-black-soft);
|
||||||
--color-background-mute: var(--vt-c-black-mute);
|
--color-background-mute: var(--vt-c-black-mute);
|
||||||
@@ -47,6 +86,10 @@
|
|||||||
|
|
||||||
--color-heading: var(--vt-c-text-dark-1);
|
--color-heading: var(--vt-c-text-dark-1);
|
||||||
--color-text: var(--vt-c-text-dark-2);
|
--color-text: var(--vt-c-text-dark-2);
|
||||||
|
|
||||||
|
/* SVG/Icon colors for dark theme */
|
||||||
|
--color-svg-fill: #ffffff;
|
||||||
|
--color-svg-stroke: #ffffff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,3 +127,36 @@ body {
|
|||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Global SVG theming */
|
||||||
|
svg {
|
||||||
|
transition:
|
||||||
|
fill 0.3s ease,
|
||||||
|
stroke 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg[fill='#000000'],
|
||||||
|
svg[fill='#000'] {
|
||||||
|
fill: var(--color-svg-fill) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg[stroke='#000000'],
|
||||||
|
svg[stroke='#000'] {
|
||||||
|
stroke: var(--color-svg-stroke) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Target paths and other SVG elements with black fill/stroke */
|
||||||
|
svg path[fill='#000000'],
|
||||||
|
svg path[fill='#000'] {
|
||||||
|
fill: var(--color-svg-fill) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg path[stroke='#000000'],
|
||||||
|
svg path[stroke='#000'] {
|
||||||
|
stroke: var(--color-svg-stroke) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Target specific attribute values commonly used */
|
||||||
|
svg g[fill='#000000'] {
|
||||||
|
fill: var(--color-svg-fill) !important;
|
||||||
|
}
|
||||||
|
|||||||
128
src/components/ThemeToggle.vue
Normal file
128
src/components/ThemeToggle.vue
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
<template>
|
||||||
|
<button
|
||||||
|
@click="toggleTheme"
|
||||||
|
class="theme-toggle"
|
||||||
|
:aria-label="isDark ? 'Switch to light mode' : 'Switch to dark mode'"
|
||||||
|
title="Toggle theme"
|
||||||
|
>
|
||||||
|
<svg v-if="isDark" class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||||||
|
<!-- Sun icon -->
|
||||||
|
<circle cx="12" cy="12" r="5" />
|
||||||
|
<line x1="12" y1="1" x2="12" y2="3" />
|
||||||
|
<line x1="12" y1="21" x2="12" y2="23" />
|
||||||
|
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
|
||||||
|
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
|
||||||
|
<line x1="1" y1="12" x2="3" y2="12" />
|
||||||
|
<line x1="21" y1="12" x2="23" y2="12" />
|
||||||
|
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
|
||||||
|
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
|
||||||
|
</svg>
|
||||||
|
<svg v-else class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
||||||
|
<!-- Moon icon -->
|
||||||
|
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, watch } from 'vue'
|
||||||
|
|
||||||
|
const isDark = ref(false)
|
||||||
|
|
||||||
|
const toggleTheme = () => {
|
||||||
|
isDark.value = !isDark.value
|
||||||
|
updateTheme()
|
||||||
|
localStorage.setItem('theme', isDark.value ? 'dark' : 'light')
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateTheme = () => {
|
||||||
|
if (isDark.value) {
|
||||||
|
document.documentElement.classList.add('dark')
|
||||||
|
document.documentElement.classList.remove('light')
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.add('light')
|
||||||
|
document.documentElement.classList.remove('dark')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const initTheme = () => {
|
||||||
|
const savedTheme = localStorage.getItem('theme')
|
||||||
|
if (savedTheme) {
|
||||||
|
isDark.value = savedTheme === 'dark'
|
||||||
|
} else {
|
||||||
|
// Check system preference as fallback
|
||||||
|
isDark.value = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
|
}
|
||||||
|
updateTheme()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initTheme()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Watch for system theme changes when no preference is saved
|
||||||
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
||||||
|
mediaQuery.addEventListener('change', (e) => {
|
||||||
|
if (!localStorage.getItem('theme')) {
|
||||||
|
isDark.value = e.matches
|
||||||
|
updateTheme()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.theme-toggle {
|
||||||
|
position: fixed;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
z-index: 1000;
|
||||||
|
background: var(--color-background-soft);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle:hover {
|
||||||
|
background: var(--color-background-mute);
|
||||||
|
border-color: var(--color-border-hover);
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
color: var(--color-text);
|
||||||
|
stroke-width: 2;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle:hover .icon {
|
||||||
|
transform: rotate(15deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure the button works well on mobile */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.theme-toggle {
|
||||||
|
top: 15px;
|
||||||
|
right: 15px;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -23,3 +23,9 @@
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.st0 {
|
||||||
|
fill: var(--color-svg-fill);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<svg
|
<svg
|
||||||
fill="#000000"
|
fill="var(--color-svg-fill)"
|
||||||
width="800px"
|
width="800px"
|
||||||
height="800px"
|
height="800px"
|
||||||
viewBox="0 0 1920 1920"
|
viewBox="0 0 1920 1920"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<svg
|
<svg
|
||||||
fill="#000000"
|
fill="var(--color-svg-fill)"
|
||||||
width="800px"
|
width="800px"
|
||||||
height="800px"
|
height="800px"
|
||||||
viewBox="0 0 32 32"
|
viewBox="0 0 32 32"
|
||||||
|
|||||||
76
src/components/icons/IconLogo.vue
Normal file
76
src/components/icons/IconLogo.vue
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<template>
|
||||||
|
<svg
|
||||||
|
version="1.0"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
:width="width"
|
||||||
|
:height="height"
|
||||||
|
viewBox="0 0 222.000000 222.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet"
|
||||||
|
class="logo-svg"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
transform="translate(0.000000,222.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="var(--color-svg-fill)"
|
||||||
|
stroke="none"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M0 1110 l0 -1110 1110 0 1110 0 0 1110 0 1110 -1110 0 -1110 0 0
|
||||||
|
-1110z m2180 0 l0 -1070 -612 0 -613 0 222 222 c265 266 282 294 251 402 -10
|
||||||
|
35 -66 96 -362 394 -193 195 -368 362 -388 373 -45 23 -115 25 -166 3 -24 -9
|
||||||
|
-115 -93 -254 -232 l-218 -216 0 597 0 597 1070 0 1070 0 0 -1070z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M124 2086 c-16 -13 -17 -18 -6 -35 9 -17 10 -25 0 -40 -9 -15 -9 -23
|
||||||
|
1 -35 11 -13 11 -19 0 -32 -10 -12 -10 -20 -1 -35 10 -15 9 -23 0 -39 -11 -17
|
||||||
|
-10 -22 2 -30 12 -7 12 -12 0 -35 -12 -23 -12 -28 0 -35 12 -7 12 -12 0 -35
|
||||||
|
-12 -23 -12 -28 0 -35 12 -7 12 -12 0 -35 -12 -23 -12 -28 0 -35 8 -6 103 -10
|
||||||
|
210 -10 209 0 236 6 203 42 -14 16 -33 18 -143 18 -70 0 -130 3 -133 7 -4 3
|
||||||
|
-1 13 6 21 9 12 9 16 0 19 -15 5 -17 39 -3 48 6 4 5 13 -3 25 -9 15 -9 25 -1
|
||||||
|
38 8 12 8 22 0 35 -8 12 -8 22 0 35 8 12 8 22 0 35 -8 12 -8 22 0 34 8 13 8
|
||||||
|
23 0 35 -8 13 -8 23 1 37 10 15 9 22 -6 35 -22 20 -100 21 -127 2z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M1199 1843 c-64 -32 -369 -325 -369 -355 0 -51 34 -29 193 130 200
|
||||||
|
199 250 226 343 187 38 -16 355 -322 399 -385 15 -21 29 -56 32 -78 10 -76 -9
|
||||||
|
-105 -190 -289 -167 -169 -190 -203 -139 -203 30 0 338 320 364 377 29 64 28
|
||||||
|
135 -1 193 -30 59 -371 400 -428 429 -61 30 -135 28 -204 -6z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M1198 1571 c-56 -57 -98 -107 -98 -118 0 -25 40 -63 66 -63 19 0 224
|
||||||
|
197 224 214 0 12 -22 51 -34 58 -34 23 -62 7 -158 -91z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M1479 1302 c-74 -73 -99 -104 -99 -123 0 -27 37 -69 60 -69 7 0 59
|
||||||
|
46 116 102 110 108 122 130 84 168 -36 36 -57 25 -161 -78z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M1675 546 c-33 -24 -3 -46 60 -46 67 0 89 -8 75 -25 -8 -10 -8 -19 1
|
||||||
|
-33 10 -16 10 -23 0 -35 -10 -12 -10 -19 0 -35 10 -16 10 -23 0 -35 -10 -12
|
||||||
|
-10 -19 0 -35 10 -16 10 -23 0 -35 -10 -12 -10 -19 0 -35 10 -16 10 -23 0 -36
|
||||||
|
-11 -13 -11 -19 0 -32 10 -13 10 -20 0 -36 -20 -32 2 -48 69 -48 67 0 89 16
|
||||||
|
69 48 -10 16 -10 23 0 35 10 12 10 19 0 35 -10 16 -10 23 0 35 10 12 10 19 0
|
||||||
|
35 -10 16 -10 23 0 35 10 12 10 19 0 35 -10 16 -10 23 0 35 10 12 10 19 0 35
|
||||||
|
-10 16 -10 23 0 36 10 12 11 19 2 30 -16 19 5 26 74 26 63 0 93 22 60 46 -27
|
||||||
|
20 -383 20 -410 0z"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
interface Props {
|
||||||
|
width?: string | number
|
||||||
|
height?: string | number
|
||||||
|
}
|
||||||
|
|
||||||
|
withDefaults(defineProps<Props>(), {
|
||||||
|
width: 125,
|
||||||
|
height: 125,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.logo-svg {
|
||||||
|
transition: fill 0.3s ease;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="#000000"
|
stroke="var(--color-svg-stroke)"
|
||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
stroke-miterlimit="10"
|
stroke-miterlimit="10"
|
||||||
d="M22.2,12.8l-3-3l5-5C23.3,4.3,22.2,4,21,4
|
d="M22.2,12.8l-3-3l5-5C23.3,4.3,22.2,4,21,4
|
||||||
|
|||||||
Reference in New Issue
Block a user