Big bang/webgune berria (#18)
* chore: netlify deployments plugina kentzen du * chore: Strapi berria instalatzen du * feat: astro instalatzen du * chore: cypress instalatzen du * feat: back eta front konektatzen ditu * feat: server side rendering egiten du * chore: Strapin enterprise edition flagak kentzen ditu * feat: euskara sartzen du * chore: Strapi bertsioa igotzen du * feat: preview modua sortzen du ingurune bariableen bidez * aurreko commitarekin doa * fix: cypress konpontzen du * chore: Strapi bertsioa igotzen du * feat: ekintza back-ean sortzen du * feat: zikloa eta erakundea sortzen ditu * feat: erakundeen kudeaketa hobetzen du * chore: pnpm erabiltzen du * feat: Strapi bertsioa igotzen du * ekintza sortzen du eta zerbitzuak eguneratzen ditu * chore: graphql erabiltzen du populazioa ekiditeko * chore: collection erabiltzen du ekintzetarako * chore: bertsioak igotzen ditu * chore: Astro bertsioa igotzen du * chore: Strapi bertsioa igotzen du * feat: home-a hasten du * feat: zig zag separadorea sortzen du * feat: zig zaga doitzen du * feat: heroa doitzen du * feat: agenda sortzen du * feat: agenda eta izan labazkide atalak konektatzen ditu * feat: home-aren edukia sortzen du * chore: app.js sartzen du WTF * feat: header-a sortzen du * feat: card-a hobetzen du * feat: footer-a sortzen du * feat: ekintzen zerrenda erakusten du * feat: zikloaren bista sortzen du * fix: header-aren estekak konpontzen ditu * chore: remove unused code * chore: components directorioa kentzen du * chore: typescript konfigurazioa hobetzen du * chore: views path-a sortzen du * feat: zikloaren deskribapena erakusten du * feat: ekintzaren bista sortzen du * feat: zig zag marra erakusten du * ignore: comment * feat: hitzordua erakusten du * feat: zikloa erakusten du * feat: Waveko erroreak errepasatzen ditu * feat: Wave birpasatzen du * feat: zerrendan irudia erakusten du * feat: karga optimizatzen du * feat: irudien formatuak kontuan hartzen ditu * feat: zikloan ekintza irudiak erakusten ditu * feat: ekintza zerrenda atontzen du * feat: header-eko estekak markatzen ditu * feat: irudi estela erakusten du * feat: responsive-a hobetzen du * feat: orri basikoa sortzen du * feat: hasiera responsive egiten du * feat: overflow konpontzen du * feat: bug-a uzten du LOL * feat: irudi estela mugikorrean aktibatzen du * feat: orri basikoa eta ekintza mugikorrean jartzen ditu * feat: mugikor menua sortzen du * feat: mugikor menua amaitzen du * feat: build estatikoa sortzen du * feat: sitemap-a sortzen du * feat: rss feed-a sortzen du * chore: ingurune aldagaiak sortzen ditu * chore: public-proxy komandoa sortzen du * feat: irudiak webp formatuan jartzen ditu * fix: irudiak erakusten ditu ekintzen zerrendan * feat: ekintza zerrendaren irudia animatzen du * refactor: extract functions * fix: animazioa konpontzen du * feat: irudi estela hobetzen du * chore: prerender aldagaiak kentzen ditu * chore: SASS warning-ak kentzen ditu * feat: ziklo eta ekintzetan H1 ezartzen du * feat: slideshow-a sortzen du * feat: ekintzak hitzorduan oinarrituta filtratzen ditu * feat: hitzorduen arabera filtratzen du eta moment kentzen du * feat: titulua aldatzen du * feat: menua eguneratzen du * feat: parte hartun deskribapena sortzen du * feat: Cloudinary konfiguratzen du * fix: cloudinary konfigurazioa konpontzen du * feat: erositako fonteak jartzen ditu
This commit is contained in:
21
front/src/views/_components/EkintzaZerrenda.astro
Normal file
21
front/src/views/_components/EkintzaZerrenda.astro
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
import { type EkintzaSnippet } from "models/Ekintza";
|
||||
import { EkintzaZerrenda as EkintzaZerrendaReact } from "./react/EkintzaZerrenda";
|
||||
|
||||
export interface Props {
|
||||
ekintzak: EkintzaSnippet[];
|
||||
title?: string;
|
||||
description?: string;
|
||||
isMainTitle?: boolean;
|
||||
}
|
||||
|
||||
const { ekintzak, title, description, isMainTitle = false } = Astro.props;
|
||||
---
|
||||
|
||||
<EkintzaZerrendaReact
|
||||
ekintzak={ekintzak}
|
||||
title={title}
|
||||
description={description}
|
||||
isMainTitle
|
||||
client:idle
|
||||
/>
|
||||
140
front/src/views/_components/Footer.astro
Normal file
140
front/src/views/_components/Footer.astro
Normal file
@@ -0,0 +1,140 @@
|
||||
---
|
||||
import Logo from "../../assets/labaLogo.svg";
|
||||
import ZigZag from "./ZigZag.astro";
|
||||
---
|
||||
|
||||
<ZigZag from="gorria-background" to="marroia" />
|
||||
<footer class="footer">
|
||||
<div class="lehenengo-lerroa">
|
||||
<Logo class="footer-logo" />
|
||||
|
||||
<address>Gazteluko plaza, 2. 31001 Iruñea, Nafarroa</address>
|
||||
</div>
|
||||
|
||||
<div class="bigarren-lerroa">
|
||||
<nav>
|
||||
<ul>
|
||||
<li class="elementu-legala">
|
||||
<a href="/lege-oharra">Lege oharra</a>
|
||||
</li>
|
||||
|
||||
<li class="elementu-legala">
|
||||
<a href="/pribatutasun-politika">Pribatutasun politika</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<nav>
|
||||
<ul class="sare-sozialak">
|
||||
<li><a href="https://twitter.com/labasarea/">X</a></li>
|
||||
<li><a href="https://www.instagram.com/labasarea/">Instagram</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<style lang="scss">
|
||||
@use "../../style/tools/toDVW.scss";
|
||||
@use "../../style/tools/mediaQueries.scss";
|
||||
@use "../../style/mixins/textFonts.scss";
|
||||
|
||||
.footer {
|
||||
padding: var(--space-05-mobile);
|
||||
|
||||
background-color: var(--marroia);
|
||||
color: var(--gorria);
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
padding: var(--space-07-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
.footer-logo {
|
||||
height: var(--space-05-mobile);
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
height: var(--space-07-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
.lehenengo-lerroa {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
border-bottom: #{toDVW.toMobileDVW(2)} solid var(--gorria);
|
||||
padding-bottom: var(--space-05-mobile);
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
padding-bottom: var(--space-07-desktop);
|
||||
|
||||
border-bottom: #{toDVW.toDesktopDVW(2)} solid var(--gorria);
|
||||
}
|
||||
}
|
||||
|
||||
.bigarren-lerroa {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: var(--space-05-mobile);
|
||||
gap: var(--space-02-mobile);
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding-top: var(--space-07-desktop);
|
||||
gap: var(--space-02-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
address {
|
||||
font-style: normal;
|
||||
text-transform: uppercase;
|
||||
text-align: end;
|
||||
|
||||
@include textFonts.captionFont;
|
||||
@include mediaQueries.aboveTablet {
|
||||
text-align: initial;
|
||||
@include textFonts.bodyFont;
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.elementu-legala {
|
||||
&:not(:last-child) {
|
||||
margin-right: var(--space-02-mobile);
|
||||
|
||||
&::after {
|
||||
content: "/";
|
||||
margin-left: var(--space-02-mobile);
|
||||
}
|
||||
}
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
&:not(:last-child) {
|
||||
margin-right: var(--space-02-desktop);
|
||||
|
||||
&::after {
|
||||
content: "/";
|
||||
margin-left: var(--space-02-desktop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sare-sozialak {
|
||||
gap: var(--space-04-desktop);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--gorria);
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
281
front/src/views/_components/Header.astro
Normal file
281
front/src/views/_components/Header.astro
Normal file
@@ -0,0 +1,281 @@
|
||||
---
|
||||
import Logo from "../../assets/labaLogo.svg";
|
||||
import Hamburger from "../../assets/hamburger.svg";
|
||||
import Close from "../../assets/close.svg";
|
||||
import ZigZagMarra from "./ZigZagMarra.astro";
|
||||
|
||||
interface Props {
|
||||
isAbsolutePosition?: boolean;
|
||||
}
|
||||
|
||||
const { isAbsolutePosition = false } = Astro.props;
|
||||
const currentPath = Astro.url.pathname;
|
||||
---
|
||||
|
||||
<header class={isAbsolutePosition ? "absolute-position" : ""}>
|
||||
{
|
||||
currentPath != "/" ? (
|
||||
<a href="/">
|
||||
<span class="visually-hidden">Laba</span>
|
||||
<Logo class="logo" />
|
||||
</a>
|
||||
) : (
|
||||
<address>
|
||||
<p>Gazteluko plaza, 2</p>
|
||||
<p>Iruñea</p>
|
||||
</address>
|
||||
)
|
||||
}
|
||||
|
||||
<button class="mobile-only menu-button" id="ham-btn"><Hamburger /></button>
|
||||
|
||||
<nav class="desktop-only">
|
||||
<h2>Menua</h2>
|
||||
<ul>
|
||||
<li><a href="/#agenda">Agenda</a></li>
|
||||
<li><a href="/#izan-labazkide">Izan Labazkide</a></li>
|
||||
<li><a href="/#parte-hartu">Parte hartu</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<nav class="desktop-only">
|
||||
<h2>Jarrai gaitzazu!</h2>
|
||||
<ul>
|
||||
<li><a href="https://mastodon.eus/@labasarea">Mastodon</a></li>
|
||||
<li><a href="https://www.instagram.com/labasarea/">Instagram</a></li>
|
||||
<li><a href="https://twitter.com/labasarea/">X</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<address class="desktop-only">
|
||||
<h2>Harremanetarako</h2>
|
||||
<a href="mailto:info@laba.eus">info@laba.eus</a>
|
||||
</address>
|
||||
</header>
|
||||
|
||||
<dialog id="ham-dialog">
|
||||
<button class="close-button" id="close-dialog"
|
||||
><Close class="menu-button" /></button
|
||||
>
|
||||
|
||||
<nav>
|
||||
<h2>Menua</h2>
|
||||
<ul>
|
||||
<li><a href="/#agenda">Agenda</a></li>
|
||||
<li><a href="/#izan-labazkide">Izan Labazkide</a></li>
|
||||
<li><a href="/#parte-hartu">Parte hartu</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<nav>
|
||||
<h2>Jarrai gaitzazu!</h2>
|
||||
<ul>
|
||||
<li><a href="https://mastodon.eus/@labasarea">Mastodon</a></li>
|
||||
<li><a href="https://www.instagram.com/labasarea/">Instagram</a></li>
|
||||
<li><a href="https://twitter.com/labasarea/">X</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<address>
|
||||
<h2>Harremanetarako</h2>
|
||||
<a href="mailto:info@laba.eus">info@laba.eus</a>
|
||||
</address>
|
||||
|
||||
<ZigZagMarra />
|
||||
|
||||
{
|
||||
currentPath === "/" ? (
|
||||
<a class="dialog-footer" href="/">
|
||||
<span class="visually-hidden">Laba</span>
|
||||
<Logo class="logo" />
|
||||
</a>
|
||||
) : (
|
||||
<address class="dialog-footer">
|
||||
<p>Gazteluko plaza, 2</p>
|
||||
<p>Iruñea</p>
|
||||
</address>
|
||||
)
|
||||
}
|
||||
</dialog>
|
||||
|
||||
<script is:inline>
|
||||
const hamBtn = document.getElementById("ham-btn");
|
||||
const dialog = document.getElementById("ham-dialog");
|
||||
const closeBtn = document.getElementById("close-dialog");
|
||||
|
||||
hamBtn?.addEventListener("click", () => {
|
||||
if (dialog) {
|
||||
dialog.showModal();
|
||||
// Esperar un tick para que el navegador "pinte" el open
|
||||
requestAnimationFrame(() => {
|
||||
dialog.classList.add("show");
|
||||
});
|
||||
document.body.classList.add("no-scroll");
|
||||
}
|
||||
});
|
||||
|
||||
closeBtn?.addEventListener("click", () => {
|
||||
if (dialog) {
|
||||
dialog.classList.remove("show");
|
||||
dialog.classList.add("hide");
|
||||
setTimeout(() => {
|
||||
dialog.close();
|
||||
dialog.classList.remove("hide");
|
||||
}, 300);
|
||||
document.body.classList.remove("no-scroll");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@use "../../style/mixins/textFonts.scss";
|
||||
@use "../../style/tools/mediaQueries.scss";
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
padding: var(--space-05-mobile);
|
||||
|
||||
z-index: 15;
|
||||
|
||||
color: var(--gorria);
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1.5fr 1fr 1fr;
|
||||
padding: var(--space-07-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
.absolute-position {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.desktop-only {
|
||||
@include mediaQueries.belowTablet {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-only {
|
||||
@include mediaQueries.aboveTablet {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: var(--space-08-mobile);
|
||||
height: auto;
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
width: var(--space-09-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0;
|
||||
|
||||
color: var(--gorria);
|
||||
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.menu-button {
|
||||
width: var(--space-06-mobile);
|
||||
height: auto;
|
||||
}
|
||||
|
||||
address {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-transform: uppercase;
|
||||
@include textFonts.bodyFont;
|
||||
}
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
gap: var(--space-03-mobile);
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
gap: var(--space-03-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
&:not(:last-child) {
|
||||
&::after {
|
||||
content: ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--gorria);
|
||||
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
position: absolute;
|
||||
right: var(--space-05-mobile);
|
||||
top: var(--space-05-mobile);
|
||||
}
|
||||
|
||||
dialog {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 100dvw;
|
||||
height: 100dvh;
|
||||
padding: var(--space-08-mobile) var(--space-05-mobile)
|
||||
var(--space-05-mobile) var(--space-05-mobile);
|
||||
|
||||
color: var(--gorria);
|
||||
|
||||
border: none;
|
||||
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -70%); /* un poco más arriba */
|
||||
transition: all 0.3s ease-out;
|
||||
|
||||
&.show {
|
||||
display: grid;
|
||||
grid-template-rows: auto auto auto auto 1fr;
|
||||
gap: var(--space-05-mobile);
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%); /* centrado */
|
||||
}
|
||||
|
||||
&.hide {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -70%); /* se va hacia arriba */
|
||||
}
|
||||
|
||||
&::backdrop {
|
||||
background: var(--gorria);
|
||||
}
|
||||
|
||||
&.hide::backdrop {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
justify-self: center;
|
||||
align-self: flex-end;
|
||||
}
|
||||
</style>
|
||||
149
front/src/views/_components/IrudiEstela.astro
Normal file
149
front/src/views/_components/IrudiEstela.astro
Normal file
@@ -0,0 +1,149 @@
|
||||
---
|
||||
import { getImageData, type ImageMedia } from "models/ImageMedia";
|
||||
|
||||
interface Props {
|
||||
mosaikoa: ImageMedia[];
|
||||
}
|
||||
|
||||
const { mosaikoa } = Astro.props;
|
||||
|
||||
const mosaikoaImageDatas = shuffle(mosaikoa).map(getImageData);
|
||||
const imagesToShow = Array.from({ length: 60 }).map(
|
||||
(_, i) => mosaikoaImageDatas[i % mosaikoaImageDatas.length]
|
||||
);
|
||||
|
||||
function shuffle<T>(array: T[]) {
|
||||
const copia = [...array];
|
||||
for (let i = copia.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[copia[i], copia[j]] = [copia[j], copia[i]];
|
||||
}
|
||||
return copia;
|
||||
}
|
||||
---
|
||||
|
||||
<div class="wrapper">
|
||||
<div class="grid">
|
||||
{
|
||||
imagesToShow.map((imageData) => (
|
||||
<div class="cell">
|
||||
<img
|
||||
src={imageData.src}
|
||||
alt={imageData.alt}
|
||||
width={imageData.width}
|
||||
height={imageData.height}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
import gsap from "gsap";
|
||||
|
||||
const cells = document.querySelectorAll(".cell img");
|
||||
|
||||
cells.forEach((img) => {
|
||||
img?.parentElement?.addEventListener("mouseenter", () => {
|
||||
gsap.to(img, {
|
||||
scale: 2,
|
||||
opacity: 1,
|
||||
duration: 0.3,
|
||||
ease: "power2.out",
|
||||
});
|
||||
});
|
||||
|
||||
img?.parentElement?.addEventListener("mouseleave", () => {
|
||||
gsap.to(img, {
|
||||
scale: 0,
|
||||
opacity: 0.4,
|
||||
duration: 1.6,
|
||||
ease: "power2.inOut",
|
||||
});
|
||||
});
|
||||
|
||||
img?.parentElement?.addEventListener("touchstart", () => {
|
||||
gsap.to(img, {
|
||||
scale: 2,
|
||||
opacity: 1,
|
||||
duration: 0.3,
|
||||
ease: "power2.out",
|
||||
});
|
||||
});
|
||||
|
||||
img?.parentElement?.addEventListener("touchend", () => {
|
||||
gsap.to(img, {
|
||||
scale: 0,
|
||||
opacity: 0.4,
|
||||
duration: 1.6,
|
||||
ease: "power2.inOut",
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@use "../../style/tools/mediaQueries.scss";
|
||||
|
||||
.wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 130%;
|
||||
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
|
||||
padding: var(--space-07-mobile);
|
||||
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
grid-template-rows: repeat(6, 1fr);
|
||||
background: var(--marroia);
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 97dvh;
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
grid-template-columns: repeat(10, 1fr);
|
||||
grid-template-rows: repeat(6, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
.cell {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: visible;
|
||||
|
||||
&:nth-child(n + 31) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
&:nth-child(n + 31) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cell img {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
will-change: transform, opacity;
|
||||
object-fit: contain;
|
||||
z-index: 10;
|
||||
}
|
||||
</style>
|
||||
135
front/src/views/_components/MarkdownParser.astro
Normal file
135
front/src/views/_components/MarkdownParser.astro
Normal file
@@ -0,0 +1,135 @@
|
||||
---
|
||||
import { marked } from "marked";
|
||||
import type { Markdown } from "models/Markdown";
|
||||
|
||||
interface Props {
|
||||
content: Markdown;
|
||||
}
|
||||
|
||||
const { content } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="markdown-wrapper" set:html={marked.parse(content, {})} />
|
||||
|
||||
<!-- global jartzen dugu, marked-en sortutako HTMLa estilizatzeko -->
|
||||
<style lang="scss" is:global>
|
||||
@use "../../style/mixins/displayFonts.scss";
|
||||
@use "../../style/tools/mediaQueries.scss";
|
||||
|
||||
.markdown-wrapper {
|
||||
p {
|
||||
&:not(:last-child) {
|
||||
margin-bottom: var(--space-04-mobile);
|
||||
}
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
&:not(:last-child) {
|
||||
margin-bottom: var(--space-05-desktop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: var(--space-04-mobile);
|
||||
|
||||
@include displayFonts.display2;
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
margin-bottom: var(--space-04-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: var(--space-03-mobile);
|
||||
|
||||
@include displayFonts.display3;
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
margin-bottom: var(--space-04-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-bottom: var(--space-02-mobile);
|
||||
|
||||
@include displayFonts.display4;
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
margin-bottom: var(--space-03-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-bottom: var(--space-02-mobile);
|
||||
|
||||
@include displayFonts.display4;
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
margin-bottom: var(--space-03-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin-bottom: var(--space-01-mobile);
|
||||
|
||||
@include displayFonts.display5;
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
margin-bottom: var(--space-02-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
h6 {
|
||||
margin-bottom: var(--space-01-mobile);
|
||||
|
||||
@include displayFonts.display6;
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
margin-bottom: var(--space-02-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--marroia);
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
width: 100%;
|
||||
margin-bottom: var(--space-01-mobile);
|
||||
|
||||
overflow-wrap: break-word;
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
margin-bottom: var(--space-02-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
ul ul {
|
||||
margin-top: var(--space-01-mobile);
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
margin-top: var(--space-02-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
margin-top: var(--space-04-mobile);
|
||||
margin-bottom: var(--space-04-mobile);
|
||||
|
||||
border: none;
|
||||
background-color: var(--gorria);
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
margin-top: var(--space-05-desktop);
|
||||
margin-bottom: var(--space-05-desktop);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
44
front/src/views/_components/ZigZag.astro
Normal file
44
front/src/views/_components/ZigZag.astro
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
type Kolorea = "transparent" | "gorria" | "gorria-background" | "marroia";
|
||||
|
||||
interface Props {
|
||||
from?: Kolorea;
|
||||
to?: Kolorea;
|
||||
}
|
||||
|
||||
const { from = "transparent", to = "transparent" } = Astro.props;
|
||||
|
||||
const colorToVar: { [key in Kolorea]: string } = {
|
||||
transparent: "transparent",
|
||||
gorria: "var(--gorria)",
|
||||
marroia: "var(--marroia)",
|
||||
"gorria-background": "var(--gorria-background)",
|
||||
};
|
||||
|
||||
const fromColor = colorToVar[from];
|
||||
const toColor = colorToVar[to];
|
||||
---
|
||||
|
||||
<div>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<style lang="scss" define:vars={{ toColor, fromColor }}>
|
||||
hr {
|
||||
height: 16px;
|
||||
background-color: var(--fromColor);
|
||||
|
||||
border: none;
|
||||
mask: conic-gradient(
|
||||
from -45deg at bottom,
|
||||
#0000,
|
||||
#000 1deg 89deg,
|
||||
#0000 90deg
|
||||
)
|
||||
50%/32px 100%;
|
||||
}
|
||||
|
||||
div {
|
||||
background-color: var(--toColor);
|
||||
}
|
||||
</style>
|
||||
41
front/src/views/_components/ZigZagMarra.astro
Normal file
41
front/src/views/_components/ZigZagMarra.astro
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
// TODO marrak elementuaren altu osoa hartzea lortu, marginak fidagarriagoak izan daitezen
|
||||
---
|
||||
|
||||
<div>
|
||||
<hr class="zig" />
|
||||
<hr class="zag" />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
hr {
|
||||
border: none;
|
||||
height: 32px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.zig {
|
||||
background:
|
||||
linear-gradient(-135deg, #fff 20px, transparent 0) 0 5px,
|
||||
linear-gradient(135deg, #fff 20px, transparent 0) 0 5px;
|
||||
background-color: transparent;
|
||||
background-position: center bottom;
|
||||
background-repeat: repeat-x;
|
||||
background-size: 20px 40px;
|
||||
z-index: 100;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.zag {
|
||||
/* oraingoz, kolore gorria bakarrik margotzen du */
|
||||
/* TODO beharrezko bada, kolorea currentColor bidez aldatu */
|
||||
background:
|
||||
linear-gradient(-135deg, var(--gorria) 20px, transparent 0) 0 5px,
|
||||
linear-gradient(135deg, var(--gorria) 20px, #fff 0) 0 5px;
|
||||
background-color: transparent;
|
||||
background-position: center bottom;
|
||||
background-repeat: repeat-x;
|
||||
background-size: 20px 40px;
|
||||
margin-top: -31px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,94 @@
|
||||
@use "../../../../style/mixins/displayFonts.scss";
|
||||
@use "../../../../style/tools/mediaQueries.scss";
|
||||
@use "sass:color";
|
||||
|
||||
.wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, [col-start] 1fr);
|
||||
gap: var(--space-05-desktop);
|
||||
}
|
||||
|
||||
.mainMediaWrapper {
|
||||
display: none;
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
display: grid;
|
||||
grid-column: col-start 1 / span 4;
|
||||
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.mainMedia {
|
||||
border-radius: 50%;
|
||||
aspect-ratio: 1;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.agendaWrapper {
|
||||
grid-column: col-start 1 / -1;
|
||||
|
||||
color: var(--gorria);
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
grid-column: col-start 5 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-top: var(--space-05-desktop);
|
||||
}
|
||||
|
||||
.zerrenda {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-04-mobile);
|
||||
|
||||
margin-top: var(--space-05-mobile);
|
||||
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
|
||||
@include mediaQueries.aboveTablet {
|
||||
gap: var(--space-04-desktop);
|
||||
margin-top: var(--space-05-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
.esteka {
|
||||
display: grid;
|
||||
gap: var(--space-04-mobile);
|
||||
grid-template-columns: 1fr auto;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
|
||||
// irudi estelaren wrapper-a ekiditeko z-index ezartzen da
|
||||
z-index: 20;
|
||||
|
||||
& {
|
||||
color: var(--gorria);
|
||||
opacity: 0.65;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@include displayFonts.display5;
|
||||
@include mediaQueries.aboveTablet {
|
||||
gap: var(--space-04-desktop);
|
||||
}
|
||||
}
|
||||
|
||||
.izenburua {
|
||||
position: relative;
|
||||
|
||||
// irudi estelaren wrapper-a ekiditeko z-index ezartzen da
|
||||
z-index: 20;
|
||||
|
||||
@include displayFonts.display2;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import React, { useState, useEffect, useRef, useMemo } from "react";
|
||||
import gsap from "gsap";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import { type EkintzaSnippet, getShortDate, getUrl } from "models/Ekintza";
|
||||
import { getImageData, type ImageData } from "models/ImageMedia";
|
||||
import styles from "./EkintzaZerrenda.module.scss";
|
||||
|
||||
interface Props {
|
||||
ekintzak: EkintzaSnippet[];
|
||||
title?: string;
|
||||
description?: string;
|
||||
isMainTitle?: boolean;
|
||||
}
|
||||
|
||||
export const EkintzaZerrenda: React.FC<Props> = ({
|
||||
title,
|
||||
description,
|
||||
ekintzak,
|
||||
isMainTitle = false,
|
||||
}) => {
|
||||
const sortedEkintzak = useMemo(
|
||||
() =>
|
||||
[...ekintzak].sort((a, b) =>
|
||||
dayjs(a.hitzordua).isBefore(b.hitzordua) ? -1 : 1
|
||||
),
|
||||
[ekintzak]
|
||||
);
|
||||
|
||||
const [activeEkintza, setActiveEkintza] = useState<EkintzaSnippet>(
|
||||
sortedEkintzak[0]
|
||||
);
|
||||
const [playInterval, setPlayInterval] = useState(true);
|
||||
|
||||
const imageToShow = activeEkintza?.mainMedia
|
||||
? getImageData(activeEkintza.mainMedia)
|
||||
: undefined;
|
||||
const imgRef = useRef<HTMLImageElement | null>(null);
|
||||
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
intervalRef.current = setInterval(() => {
|
||||
if (!playInterval) {
|
||||
return;
|
||||
}
|
||||
|
||||
setActiveEkintza(
|
||||
sortedEkintzak[Math.floor(Math.random() * sortedEkintzak.length)]
|
||||
);
|
||||
}, 1800);
|
||||
|
||||
return () => {
|
||||
if (intervalRef.current) clearInterval(intervalRef.current);
|
||||
};
|
||||
}, [playInterval]);
|
||||
|
||||
useEffect(() => {
|
||||
if (imgRef.current) {
|
||||
gsap.fromTo(
|
||||
imgRef.current,
|
||||
{ autoAlpha: 0, scale: 1.05 },
|
||||
{ autoAlpha: 1, scale: 1, duration: 0.5, ease: "power2.out" }
|
||||
);
|
||||
}
|
||||
}, [activeEkintza]);
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<div aria-hidden className={styles.mainMediaWrapper}>
|
||||
{imageToShow && (
|
||||
<img
|
||||
ref={imgRef}
|
||||
className={styles.mainMedia}
|
||||
alt={imageToShow.alt}
|
||||
src={imageToShow.src}
|
||||
width={imageToShow.width}
|
||||
height={imageToShow.height}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.agendaWrapper}>
|
||||
{title && (
|
||||
<>
|
||||
{isMainTitle ? (
|
||||
<h1 className={styles.izenburua}>{title}</h1>
|
||||
) : (
|
||||
<h2 className={styles.izenburua}>{title}</h2>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{description && <p className={styles.description}>{description}</p>}
|
||||
|
||||
<ul className={styles.zerrenda}>
|
||||
{sortedEkintzak.map((ekintza) => (
|
||||
<li
|
||||
key={ekintza.id}
|
||||
onMouseEnter={() => handleMouseEnter(ekintza)}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
<a
|
||||
className={`${styles.esteka} ${activeEkintza?.id === ekintza.id && styles.active}`}
|
||||
href={getUrl(ekintza)}
|
||||
>
|
||||
<span>{ekintza.izenburua}</span>
|
||||
<span>{getShortDate(ekintza)}</span>
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
function handleMouseEnter(ekintza: EkintzaSnippet) {
|
||||
setPlayInterval(false);
|
||||
setActiveEkintza(ekintza);
|
||||
}
|
||||
|
||||
function handleMouseLeave() {
|
||||
setPlayInterval(true);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export { EkintzaZerrenda } from "./EkintzaZerrenda";
|
||||
Reference in New Issue
Block a user