generated from boboko/starter
homepage stuff and text animation fix
This commit is contained in:
Generated
+324
-238
File diff suppressed because it is too large
Load Diff
+43
-22
@@ -36,6 +36,13 @@ @layer base {
|
||||
color: #000;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* Browsers don't give <button> a pointer cursor by default (unlike <a>),
|
||||
and Tailwind's Preflight stopped forcing it a few versions back — so
|
||||
every button sitewide needs it set explicitly, once, here. */
|
||||
button:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes back-to-top-spin {
|
||||
@@ -47,15 +54,6 @@ @keyframes back-to-top-spin {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes text-flicker-in {
|
||||
0%, 60% {
|
||||
opacity: 0;
|
||||
}
|
||||
70%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════
|
||||
COMPONENTS
|
||||
═══════════════════════════════════════════════════════════════════ */
|
||||
@@ -302,25 +300,48 @@ @layer components {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
/* ── Text flicker — word switches from regular to italic/bold once
|
||||
its .is-visible ancestor appears; add data-text="<same word>" ── */
|
||||
.text-flicker {
|
||||
position: relative;
|
||||
/* ── Text dance — the word itself toggles font-weight/font-style
|
||||
(normal → bold+italic) three times, then stays bold+italic, once
|
||||
its .is-visible ancestor appears (pair with the `appear` Stimulus
|
||||
controller — data-controller="appear" data-appear-visible-class
|
||||
="is-visible"); add data-text="<same word>" ── */
|
||||
.text-dance {
|
||||
display: inline-block;
|
||||
font-weight: inherit;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.text-flicker::after {
|
||||
/* Layout-shift guard: reserve the wider bold+italic width up front.
|
||||
A zero-height, invisible line contributes its (wider)
|
||||
shrink-to-fit width to the inline-block box, so the box never
|
||||
has to grow once the animation starts — nothing around the word
|
||||
moves. Trade-off: since the real word starts out narrower and
|
||||
left-aligned, this leaves a small trailing gap after it until
|
||||
the first bold+italic pulse fills the box. (A variable-font
|
||||
weight axis would be a second way to smooth this out, but
|
||||
Manrope ships here as separate static weight files, not a
|
||||
variable font, so there's no axis to animate.) */
|
||||
.text-dance::before {
|
||||
content: attr(data-text);
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
font-weight: 700;
|
||||
display: block;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
font-weight: 800;
|
||||
font-style: italic;
|
||||
font-weight: extra-bold;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.is-visible .text-flicker::after {
|
||||
animation: text-flicker-in 0.7s ease 3 forwards;
|
||||
.is-visible .text-dance {
|
||||
animation: text-dance 0.8s ease 3 forwards;
|
||||
animation-delay: var(--dance-delay, 0s);
|
||||
}
|
||||
}
|
||||
|
||||
/* Replayed 3 times via animation-iteration-count on .is-visible
|
||||
.text-dance above — each iteration starts back at 0% (normal) and
|
||||
snaps to 100% (bold+italic); forwards fill holds the final
|
||||
iteration's 100% state after it ends, so the word settles there. */
|
||||
@keyframes text-dance {
|
||||
0%, 60% { font-weight: inherit; font-style: normal; }
|
||||
70%, 100% { font-weight: 800; font-style: italic; }
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ class="text-h2 leading-tight"
|
||||
data-controller="appear"
|
||||
data-appear-visible-class="is-visible"
|
||||
>
|
||||
<span class="text-flicker" data-text="Γράψου">Γράψου</span>
|
||||
<span class="text-dance" data-text="Γράψου">Γράψου</span>
|
||||
στο
|
||||
<span class="text-flicker" data-text="newsletter">newsletter</span>
|
||||
<span class="text-dance [--dance-delay:200ms]" data-text="newsletter">newsletter</span>
|
||||
μας
|
||||
</h2>
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
'href' => null,
|
||||
'type' => 'button',
|
||||
'size' => 'lg',
|
||||
'position' => 'relative',
|
||||
])
|
||||
|
||||
@php
|
||||
@@ -14,7 +15,14 @@
|
||||
default => 'py-5 px-[46px] text-[19px]',
|
||||
};
|
||||
|
||||
$class = 'btn-primary relative isolate inline-flex items-center justify-center border border-black font-display font-bold italic text-black cursor-pointer no-underline uppercase ' . $sizeClasses;
|
||||
// $position defaults to 'relative' (needed so the ::before/::after layers
|
||||
// in .btn-primary position against the button itself), but callers that
|
||||
// need to place the button absolutely (e.g. a hover-reveal CTA over a
|
||||
// product image) must pass position="absolute" here rather than adding
|
||||
// "absolute" via the class prop — Tailwind's generated stylesheet always
|
||||
// orders the "relative" utility after "absolute", so on a class clash
|
||||
// "relative" silently wins and the button never actually gets positioned.
|
||||
$class = 'btn-primary '.$position.' isolate inline-flex items-center justify-center border border-black font-display font-bold italic text-black cursor-pointer no-underline uppercase ' . $sizeClasses;
|
||||
|
||||
$attrs = $href
|
||||
? $attributes->merge(['href' => $href, 'class' => $class])
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
'href' => '#',
|
||||
])
|
||||
|
||||
<div class="group relative">
|
||||
<a href="{{ $href }}" class="block border border-black overflow-hidden bg-white mb-4 relative -z-1">
|
||||
<div class="group">
|
||||
<div class="relative flex items-center justify-center mb-4">
|
||||
<a href="{{ $href }}" class="block w-full border border-black overflow-hidden bg-white">
|
||||
@if($image)
|
||||
<img
|
||||
src="{{ $image }}"
|
||||
@@ -21,8 +22,9 @@ class="w-full h-auto block"
|
||||
@endif
|
||||
</a>
|
||||
|
||||
<div class="absolute inset-x-0 top-0 bottom-[calc(theme(spacing.4)+1.5rem+0.25rem)] flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-100 ">
|
||||
<x-ui.button size="md">Προσθήκη στο καλάθι</x-ui.button>
|
||||
<x-ui.button size="md" position="absolute" class="opacity-0 group-hover:opacity-100 transition-opacity duration-100">
|
||||
Προσθήκη στο καλάθι
|
||||
</x-ui.button>
|
||||
</div>
|
||||
|
||||
<div class="flex items-baseline justify-between gap-4">
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
</svg>
|
||||
|
||||
<h1
|
||||
class="font-display font-semibold text-6xl lg:text-7xl leading-tight"
|
||||
class="font-display font-semibold text-6xl lg:text-[80px] leading-tight"
|
||||
aria-label="Ό,τι φαντάζεσαι, το τυπώνουμε"
|
||||
data-controller="appear"
|
||||
data-appear-visible-class="is-visible"
|
||||
>
|
||||
Ό,τι <span class="text-flicker" data-text="φαντάζεσαι">φαντάζεσαι</span>,<br>
|
||||
το <span class="text-flicker" data-text="τυπώνουμε">τυπώνουμε</span>
|
||||
Ό,τι <span class="text-dance" data-text="φαντάζεσαι">φαντάζεσαι</span>,<br>
|
||||
το <span class="text-dance [--dance-delay:200ms]" data-text="τυπώνουμε">τυπώνουμε</span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -31,20 +31,19 @@ class="font-display font-semibold text-6xl lg:text-7xl leading-tight"
|
||||
type="button"
|
||||
data-action="carousel#prev"
|
||||
aria-label="Προηγούμενο προϊόν"
|
||||
class="absolute left-4 lg:left-8 top-1/2 -translate-y-1/2 hover:opacity-60 transition-opacity"
|
||||
class="absolute left-4 lg:left-8 top-1/2 z-10 -translate-y-1/2 hover:-translate-x-1 transition duration-500"
|
||||
>
|
||||
<x-ui.icon name="arrow-left" :size="62" class="[&_path]:stroke-2" />
|
||||
</button>
|
||||
|
||||
<div class="w-full ">
|
||||
<div class="w-full h-full">
|
||||
@foreach($heroProducts as $product)
|
||||
<a
|
||||
href="{{ $product['href'] }}"
|
||||
<div
|
||||
data-carousel-target="slide"
|
||||
class="{{ $loop->first ? '' : 'hidden' }} block"
|
||||
class="{{ $loop->first ? '' : 'hidden' }} group h-full flex flex-col justify-between"
|
||||
>
|
||||
<div class="flex items-center justify-center">
|
||||
<div class="border border-black bg-white mb-16 flex items-center justify-center overflow-hidden max-w-sm">
|
||||
<div class="relative flex items-center justify-center">
|
||||
<a href="{{ $product['href'] }}" class="block border border-black bg-white flex items-center justify-center overflow-hidden max-w-sm">
|
||||
@if($product['image'])
|
||||
<img
|
||||
src="{{ $product['image'] }}"
|
||||
@@ -58,15 +57,22 @@ class="w-full h-full object-cover"
|
||||
@else
|
||||
<span class="text-neutral-500 text-sm">Χωρίς εικόνα</span>
|
||||
@endif
|
||||
</a>
|
||||
|
||||
<x-ui.button size="md" position="absolute" class="opacity-0 group-hover:opacity-100 transition-opacity duration-100">
|
||||
Προσθήκη στο καλάθι
|
||||
</x-ui.button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-baseline justify-between gap-4">
|
||||
<span class="font-display font-bold text-2xl">{{ $product['name'] }}</span>
|
||||
<a href="{{ $product['href'] }}" class="font-display font-bold text-2xl leading-snug hover:text-brand">
|
||||
{{ $product['name'] }}
|
||||
</a>
|
||||
@if($product['price'] !== null)
|
||||
<span class="font-bold text-xl shrink-0"><x-ui.price :amount="$product['price']" /></span>
|
||||
@endif
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@@ -74,7 +80,7 @@ class="w-full h-full object-cover"
|
||||
type="button"
|
||||
data-action="carousel#next"
|
||||
aria-label="Επόμενο προϊόν"
|
||||
class="absolute right-4 lg:right-8 top-1/2 -translate-y-1/2 hover:opacity-60 transition-opacity"
|
||||
class="absolute right-4 lg:right-8 top-1/2 z-10 -translate-y-1/2 hover:translate-x-1 transition duration-500"
|
||||
>
|
||||
<x-ui.icon name="arrow-right" :size="62" class="[&_path]:stroke-2"/>
|
||||
</button>
|
||||
@@ -117,7 +123,7 @@ class="absolute right-4 lg:right-8 top-1/2 -translate-y-1/2 hover:opacity-60 tra
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-6 px-8 py-12">
|
||||
<button type="button" data-action="carousel#prev" aria-label="Προηγούμενα προϊόντα" class="shrink-0 hover:opacity-60 transition-opacity">
|
||||
<button type="button" data-action="carousel#prev" aria-label="Προηγούμενα προϊόντα" class="shrink-0 hover:-translate-x-0.5 hover:opacity-60 transition duration-500">
|
||||
<x-ui.icon name="arrow-left" :size="32" />
|
||||
</button>
|
||||
|
||||
@@ -138,7 +144,7 @@ class="absolute right-4 lg:right-8 top-1/2 -translate-y-1/2 hover:opacity-60 tra
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
<button type="button" data-action="carousel#next" aria-label="Επόμενα προϊόντα" class="shrink-0 hover:opacity-60 transition-opacity">
|
||||
<button type="button" data-action="carousel#next" aria-label="Επόμενα προϊόντα" class="shrink-0 hover:translate-x-0.5 hover:opacity-60 transition duration-500">
|
||||
<x-ui.icon name="arrow-right" :size="32" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user