Compare commits
No commits in common. "9ab634483519190574228c5ba7234a51ffafaed3" and "c4456d587cceaaafd9c3981d7f30a03d330bad23" have entirely different histories.
9ab6344835
...
c4456d587c
74 changed files with 772 additions and 4038 deletions
15
.gitignore
vendored
15
.gitignore
vendored
|
|
@ -57,17 +57,4 @@ Icon
|
|||
# Claude settings
|
||||
# ---------------
|
||||
|
||||
/.claude
|
||||
|
||||
# Node.js
|
||||
# ---------------
|
||||
|
||||
node_modules/
|
||||
npm-debug.log*
|
||||
*.log
|
||||
|
||||
# Build
|
||||
# ---------------
|
||||
|
||||
dist/
|
||||
node_modules/
|
||||
/.claude
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 338 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 473 B |
Binary file not shown.
Binary file not shown.
46
index.html
46
index.html
|
|
@ -1,46 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>World Game - Play to Engage</title>
|
||||
<meta name="description" content="World Game - Création de jeux et expériences interactives">
|
||||
|
||||
<!-- This file is only used during development with Vite -->
|
||||
<!-- In production, Kirby's header.php will be used -->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
|
||||
<!-- Mock Kirby data for development -->
|
||||
<script>
|
||||
window.__KIRBY__ = {
|
||||
page: {
|
||||
id: 'home',
|
||||
template: 'home',
|
||||
url: '/',
|
||||
uri: ''
|
||||
},
|
||||
site: {
|
||||
title: 'World Game',
|
||||
url: 'http://localhost:8000',
|
||||
language: 'fr',
|
||||
languages: [
|
||||
{ code: 'fr', name: 'Français' },
|
||||
{ code: 'en', name: 'English' }
|
||||
],
|
||||
logo: null,
|
||||
navigation: [
|
||||
{ label_fr: 'Accueil', label_en: 'Home', url: '/', isActive: true },
|
||||
{ label_fr: 'Expertise', label_en: 'Expertise', url: '/expertise', isActive: false },
|
||||
{ label_fr: 'Portfolio', label_en: 'Portfolio', url: '/portfolio', isActive: false },
|
||||
{ label_fr: 'Jouer', label_en: 'Play', url: '/jouer', isActive: false },
|
||||
{ label_fr: 'À propos', label_en: 'About', url: '/a-propos', isActive: false },
|
||||
{ label_fr: 'Blog', label_en: 'Blog', url: '/blog', isActive: false }
|
||||
]
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1385
package-lock.json
generated
1385
package-lock.json
generated
File diff suppressed because it is too large
Load diff
29
package.json
29
package.json
|
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
"name": "world-game-website",
|
||||
"version": "1.0.0",
|
||||
"description": "World Game - Svelte + Kirby",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"kirby:dev": "php -S localhost:8000"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://forge.studio-variable.com/studio-variable/world-game.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "6.0.0",
|
||||
"gsap": "^3.14.2",
|
||||
"navaid": "^1.2.0",
|
||||
"svelte": "5.0.0",
|
||||
"vite": "7.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"fs-extra": "^11.3.3"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
<?php
|
||||
|
||||
return function ($page, $kirby, $site) {
|
||||
// Generic page data available in all templates
|
||||
$genericData = [
|
||||
'title' => $page->title()->value(),
|
||||
'url' => $page->url(),
|
||||
'uri' => $page->uri(),
|
||||
'template' => $page->intendedTemplate()->name(),
|
||||
'modified' => $page->modified('Y-m-d'),
|
||||
'site' => [
|
||||
'title' => $site->site_title()->value(),
|
||||
'url' => $site->url(),
|
||||
'logo' => $site->logo()->toFile()?->url(),
|
||||
'language' => $kirby->language()?->code() ?? 'fr',
|
||||
'languages' => $kirby->languages()->map(function($l) {
|
||||
return [
|
||||
'code' => $l->code(),
|
||||
'name' => $l->name()
|
||||
];
|
||||
})->values(),
|
||||
'navigation' => $site->main_navigation()->toStructure()->map(function($item) use ($kirby) {
|
||||
$linkedPage = $item->link()->toPages()->first();
|
||||
return [
|
||||
'label_fr' => $item->label_fr()->value(),
|
||||
'label_en' => $item->label_en()->value(),
|
||||
'url' => $linkedPage?->url(),
|
||||
'isActive' => $linkedPage?->isOpen() ?? false
|
||||
];
|
||||
})->values()
|
||||
]
|
||||
];
|
||||
|
||||
return [
|
||||
'genericData' => $genericData
|
||||
];
|
||||
};
|
||||
|
|
@ -1,2 +1,82 @@
|
|||
<!-- Footer -->
|
||||
<footer class="site-footer">
|
||||
<div class="site-footer__container">
|
||||
<!-- Logo & Info -->
|
||||
<div class="site-footer__brand">
|
||||
<?php if ($logo = $site->logo()->toFile()): ?>
|
||||
<img src="<?= $logo->url() ?>" alt="<?= $site->site_title() ?>" class="site-footer__logo">
|
||||
<?php else: ?>
|
||||
<span class="site-footer__logo-text"><?= $site->site_title() ?></span>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($site->site_tagline()->isNotEmpty()): ?>
|
||||
<p class="site-footer__tagline"><?= $site->site_tagline() ?></p>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<!-- Contact -->
|
||||
<div class="site-footer__contact">
|
||||
<?php if ($site->contact_email()->isNotEmpty()): ?>
|
||||
<a href="mailto:<?= $site->contact_email() ?>" class="site-footer__email">
|
||||
<?= $site->contact_email() ?>
|
||||
</a>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($site->contact_phone()->isNotEmpty()): ?>
|
||||
<a href="tel:<?= $site->contact_phone() ?>" class="site-footer__phone">
|
||||
<?= $site->contact_phone() ?>
|
||||
</a>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($site->contact_address()->isNotEmpty()): ?>
|
||||
<address class="site-footer__address">
|
||||
<?= $site->contact_address()->kt() ?>
|
||||
</address>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<!-- Social Links -->
|
||||
<div class="site-footer__social">
|
||||
<?php if ($site->social_linkedin()->isNotEmpty()): ?>
|
||||
<a href="<?= $site->social_linkedin() ?>" class="site-footer__social-link" target="_blank" rel="noopener noreferrer">
|
||||
LinkedIn
|
||||
</a>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($site->social_twitter()->isNotEmpty()): ?>
|
||||
<a href="<?= $site->social_twitter() ?>" class="site-footer__social-link" target="_blank" rel="noopener noreferrer">
|
||||
Twitter
|
||||
</a>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($site->social_instagram()->isNotEmpty()): ?>
|
||||
<a href="<?= $site->social_instagram() ?>" class="site-footer__social-link" target="_blank" rel="noopener noreferrer">
|
||||
Instagram
|
||||
</a>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($site->social_youtube()->isNotEmpty()): ?>
|
||||
<a href="<?= $site->social_youtube() ?>" class="site-footer__social-link" target="_blank" rel="noopener noreferrer">
|
||||
YouTube
|
||||
</a>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<!-- Mentions légales -->
|
||||
<?php if ($pdf = $site->mentions_legales()->toFile()): ?>
|
||||
<div class="site-footer__legal">
|
||||
<a href="<?= $pdf->url() ?>" target="_blank">Mentions légales</a>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Copyright -->
|
||||
<div class="site-footer__copyright">
|
||||
<p>© <?= date('Y') ?> <?= $site->site_title() ?>. Tous droits réservés.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Scripts -->
|
||||
<?= js('assets/js/main.js') ?>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/png" href="<?= url('assets/favicon.png') ?>">
|
||||
|
||||
<!-- Styles -->
|
||||
<?= css('assets/css/main.css') ?>
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content="<?= $page->meta_title()->or($page->title()) ?>">
|
||||
<meta property="og:description" content="<?= $page->meta_description()->or($site->site_description()) ?>">
|
||||
|
|
@ -18,16 +21,53 @@
|
|||
<?php if ($cover = $page->cover()->toFile()): ?>
|
||||
<meta property="og:image" content="<?= $cover->url() ?>">
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (file_exists('assets/dist')): ?>
|
||||
<!-- Production: Load compiled assets -->
|
||||
<script type="module" src="<?= url('assets/dist/index.js') ?>" defer></script>
|
||||
<link rel="stylesheet" href="<?= url('assets/dist/index.css') ?>">
|
||||
<?php else: ?>
|
||||
<!-- Development: Load from Vite dev server -->
|
||||
<script type="module" src="http://localhost:5173/@vite/client" defer></script>
|
||||
<script type="module" src="http://localhost:5173/src/main.js" defer></script>
|
||||
<?php endif ?>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<body class="template-<?= $page->template() ?>">
|
||||
<!-- Header -->
|
||||
<header class="site-header">
|
||||
<div class="site-header__container">
|
||||
<!-- Logo -->
|
||||
<a href="<?= $site->url() ?>" class="site-header__logo">
|
||||
<?php if ($logo = $site->logo()->toFile()): ?>
|
||||
<img src="<?= $logo->url() ?>" alt="<?= $site->site_title() ?>">
|
||||
<?php else: ?>
|
||||
<span class="site-header__logo-text"><?= $site->site_title() ?></span>
|
||||
<?php endif ?>
|
||||
</a>
|
||||
|
||||
<!-- Navigation -->
|
||||
<nav class="site-header__nav">
|
||||
<ul class="site-nav">
|
||||
<?php foreach ($site->main_navigation()->toStructure() as $item): ?>
|
||||
<?php $linkedPage = $item->link()->toPages()->first() ?>
|
||||
<?php if ($linkedPage): ?>
|
||||
<li class="site-nav__item <?= $linkedPage->isOpen() ? 'is-active' : '' ?>">
|
||||
<a href="<?= $linkedPage->url() ?>">
|
||||
<?= $kirby->language()?->code() === 'en' ? $item->label_en() : $item->label_fr() ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<!-- Language Switcher -->
|
||||
<?php if ($kirby->languages()->count() > 1): ?>
|
||||
<div class="site-header__lang">
|
||||
<?php foreach ($kirby->languages() as $lang): ?>
|
||||
<a href="<?= $page->url($lang->code()) ?>"
|
||||
class="site-lang__link <?= $lang->code() === $kirby->language()?->code() ? 'is-active' : '' ?>">
|
||||
<?= strtoupper($lang->code()) ?>
|
||||
</a>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Mobile Menu Toggle -->
|
||||
<button class="site-header__toggle" aria-label="Menu">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
$specificData = [
|
||||
'intro' => [
|
||||
'title' => $page->intro_title()->value(),
|
||||
'text' => $page->intro_text()->value()
|
||||
],
|
||||
'mission' => [
|
||||
'title' => $page->mission_title()->value(),
|
||||
'text' => $page->mission_text()->toBlocks()
|
||||
],
|
||||
'manifesto' => [
|
||||
'title' => $page->manifesto_title()->value(),
|
||||
'text' => $page->manifesto_text()->toBlocks()
|
||||
],
|
||||
'team' => [
|
||||
'title' => $page->team_title()->value(),
|
||||
'members' => $page->team_members()->toStructure()->map(function($member) {
|
||||
return [
|
||||
'name' => $member->name()->value(),
|
||||
'role' => $member->role()->value(),
|
||||
'bio' => $member->bio()->value(),
|
||||
'photo' => $member->photo()->toFile()?->url(),
|
||||
'linkedin' => $member->linkedin()->value(),
|
||||
'twitter' => $member->twitter()->value()
|
||||
];
|
||||
})->values()
|
||||
]
|
||||
];
|
||||
|
||||
$pageData = array_merge($genericData, $specificData);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($pageData);
|
||||
|
|
@ -1,2 +1,81 @@
|
|||
<?php snippet('header') ?>
|
||||
|
||||
<main class="about">
|
||||
<!-- Intro Section -->
|
||||
<section class="about__intro">
|
||||
<h1 class="about__title"><?= $page->intro_title() ?></h1>
|
||||
|
||||
<?php if ($page->intro_text()->isNotEmpty()): ?>
|
||||
<p class="about__subtitle"><?= $page->intro_text() ?></p>
|
||||
<?php endif ?>
|
||||
</section>
|
||||
|
||||
<!-- Mission Section -->
|
||||
<?php if ($page->mission_text()->isNotEmpty()): ?>
|
||||
<section class="about__mission">
|
||||
<h2 class="about__section-title"><?= $page->mission_title() ?></h2>
|
||||
<div class="about__section-content">
|
||||
<?= $page->mission_text()->toBlocks() ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Manifesto Section -->
|
||||
<?php if ($page->manifesto_text()->isNotEmpty()): ?>
|
||||
<section class="about__manifesto">
|
||||
<h2 class="about__section-title"><?= $page->manifesto_title() ?></h2>
|
||||
<div class="about__section-content">
|
||||
<?= $page->manifesto_text()->toBlocks() ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Team Section -->
|
||||
<?php if ($page->team_members()->isNotEmpty()): ?>
|
||||
<section class="about__team">
|
||||
<h2 class="about__section-title"><?= $page->team_title() ?></h2>
|
||||
|
||||
<div class="about__team-grid">
|
||||
<?php foreach ($page->team_members()->toStructure() as $member): ?>
|
||||
<article class="team-card">
|
||||
<?php if ($photo = $member->photo()->toFile()): ?>
|
||||
<div class="team-card__photo">
|
||||
<img src="<?= $photo->url() ?>" alt="<?= $member->name() ?>">
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<div class="team-card__info">
|
||||
<h3 class="team-card__name"><?= $member->name() ?></h3>
|
||||
<p class="team-card__role"><?= $member->role() ?></p>
|
||||
|
||||
<?php if ($member->bio()->isNotEmpty()): ?>
|
||||
<p class="team-card__bio"><?= $member->bio() ?></p>
|
||||
<?php endif ?>
|
||||
|
||||
<div class="team-card__social">
|
||||
<?php if ($member->linkedin()->isNotEmpty()): ?>
|
||||
<a href="<?= $member->linkedin() ?>" target="_blank" class="team-card__social-link">
|
||||
LinkedIn
|
||||
</a>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($member->twitter()->isNotEmpty()): ?>
|
||||
<a href="<?= $member->twitter() ?>" target="_blank" class="team-card__social-link">
|
||||
Twitter
|
||||
</a>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
|
||||
<nav class="about__team-nav">
|
||||
<button class="about__team-prev">← Précédent</button>
|
||||
<button class="about__team-next">Suivant →</button>
|
||||
</nav>
|
||||
</section>
|
||||
<?php endif ?>
|
||||
</main>
|
||||
|
||||
<?php snippet('footer') ?>
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
$related = $page->related_articles()->toPages();
|
||||
if ($related->isEmpty()) {
|
||||
$related = $page->siblings()->listed()->not($page)->shuffle()->limit(3);
|
||||
}
|
||||
|
||||
$specificData = [
|
||||
'date' => $page->date()->toDate('Y-m-d'),
|
||||
'date_formatted' => $page->date()->toDate('d/m/Y'),
|
||||
'intro' => $page->intro()->value(),
|
||||
'author' => [
|
||||
'name' => $page->author_name()->value(),
|
||||
'role' => $page->author_role()->value(),
|
||||
'photo' => $page->author_photo()->toFile()?->url()
|
||||
],
|
||||
'cover' => $page->cover()->toFile()?->url(),
|
||||
'content' => $page->article_content()->toBlocks(),
|
||||
'tags' => $page->tags()->split(),
|
||||
'related' => $related->map(function($rec) {
|
||||
return [
|
||||
'title' => $rec->title()->value(),
|
||||
'url' => $rec->url(),
|
||||
'category' => $rec->category()->value(),
|
||||
'cover' => $rec->cover()->toFile()?->thumb(['width' => 400])->url()
|
||||
];
|
||||
})->values(),
|
||||
'parent_url' => $page->parent()->url()
|
||||
];
|
||||
|
||||
$pageData = array_merge($genericData, $specificData);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($pageData);
|
||||
|
|
@ -1,2 +1,101 @@
|
|||
<?php snippet('header') ?>
|
||||
|
||||
<main class="article">
|
||||
<article class="article__content">
|
||||
<!-- Header -->
|
||||
<header class="article__header">
|
||||
<?php if ($page->date()->isNotEmpty()): ?>
|
||||
<time class="article__date" datetime="<?= $page->date()->toDate('Y-m-d') ?>">
|
||||
Publié le <?= $page->date()->toDate('d/m/Y') ?>
|
||||
</time>
|
||||
<?php endif ?>
|
||||
|
||||
<h1 class="article__title"><?= $page->title() ?></h1>
|
||||
|
||||
<?php if ($page->intro()->isNotEmpty()): ?>
|
||||
<p class="article__intro"><?= $page->intro() ?></p>
|
||||
<?php endif ?>
|
||||
</header>
|
||||
|
||||
<!-- Author -->
|
||||
<?php if ($page->author_name()->isNotEmpty()): ?>
|
||||
<div class="article__author">
|
||||
<?php if ($photo = $page->author_photo()->toFile()): ?>
|
||||
<img src="<?= $photo->url() ?>" alt="<?= $page->author_name() ?>" class="article__author-photo">
|
||||
<?php endif ?>
|
||||
|
||||
<div class="article__author-info">
|
||||
<span class="article__author-name"><?= $page->author_name() ?></span>
|
||||
<?php if ($page->author_role()->isNotEmpty()): ?>
|
||||
<span class="article__author-role"><?= $page->author_role() ?></span>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Cover Image -->
|
||||
<?php if ($cover = $page->cover()->toFile()): ?>
|
||||
<figure class="article__cover">
|
||||
<img src="<?= $cover->url() ?>" alt="<?= $page->title() ?>">
|
||||
</figure>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="article__body">
|
||||
<?= $page->article_content()->toBlocks() ?>
|
||||
</div>
|
||||
|
||||
<!-- Tags -->
|
||||
<?php if ($page->tags()->isNotEmpty()): ?>
|
||||
<div class="article__tags">
|
||||
<?php foreach ($page->tags()->split() as $tag): ?>
|
||||
<span class="article__tag"><?= $tag ?></span>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</article>
|
||||
|
||||
<!-- Recommendations -->
|
||||
<?php
|
||||
$related = $page->related_articles()->toPages();
|
||||
if ($related->isEmpty()) {
|
||||
$related = $page->siblings()->listed()->not($page)->shuffle()->limit(3);
|
||||
}
|
||||
?>
|
||||
|
||||
<?php if ($related->isNotEmpty()): ?>
|
||||
<section class="article__recommendations">
|
||||
<h2 class="article__recommendations-title">Nos recommandations</h2>
|
||||
<a href="<?= $page->parent()->url() ?>" class="article__recommendations-link">Voir tous les articles →</a>
|
||||
|
||||
<div class="article__recommendations-grid">
|
||||
<?php foreach ($related as $rec): ?>
|
||||
<article class="recommendation-card">
|
||||
<?php if ($cover = $rec->cover()->toFile()): ?>
|
||||
<div class="recommendation-card__cover">
|
||||
<img src="<?= $cover->thumb(['width' => 400])->url() ?>" alt="<?= $rec->title() ?>">
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($rec->category()->isNotEmpty()): ?>
|
||||
<span class="recommendation-card__category"><?= $rec->category() ?></span>
|
||||
<?php endif ?>
|
||||
|
||||
<h3 class="recommendation-card__title">
|
||||
<a href="<?= $rec->url() ?>"><?= $rec->title() ?></a>
|
||||
</h3>
|
||||
</article>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Navigation -->
|
||||
<nav class="article__nav">
|
||||
<a href="<?= $page->parent()->url() ?>" class="article__nav-back">
|
||||
← Tous les articles
|
||||
</a>
|
||||
</nav>
|
||||
</main>
|
||||
|
||||
<?php snippet('footer') ?>
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
$specificData = [
|
||||
'intro' => [
|
||||
'title' => $page->intro_title()->value(),
|
||||
'text' => $page->intro_text()->value()
|
||||
],
|
||||
'articles' => $page->children()->listed()->sortBy('date', 'desc')->map(function($article) {
|
||||
return [
|
||||
'title' => $article->title()->value(),
|
||||
'slug' => $article->slug(),
|
||||
'url' => $article->url(),
|
||||
'date' => $article->date()->toDate('Y-m-d'),
|
||||
'date_formatted' => $article->date()->toDate('d/m/Y'),
|
||||
'intro' => $article->intro()->excerpt(200),
|
||||
'cover' => $article->cover()->toFile()?->url(),
|
||||
'author_name' => $article->author_name()->value(),
|
||||
'author_photo' => $article->author_photo()->toFile()?->url()
|
||||
];
|
||||
})->values()
|
||||
];
|
||||
|
||||
$pageData = array_merge($genericData, $specificData);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($pageData);
|
||||
|
|
@ -1,2 +1,61 @@
|
|||
<?php snippet('header') ?>
|
||||
|
||||
<main class="blog">
|
||||
<!-- Intro Section -->
|
||||
<section class="blog__intro">
|
||||
<h1 class="blog__title"><?= $page->intro_title() ?></h1>
|
||||
|
||||
<?php if ($page->intro_text()->isNotEmpty()): ?>
|
||||
<p class="blog__subtitle"><?= $page->intro_text() ?></p>
|
||||
<?php endif ?>
|
||||
</section>
|
||||
|
||||
<!-- Articles List -->
|
||||
<section class="blog__articles">
|
||||
<?php foreach ($page->children()->listed()->sortBy('date', 'desc') as $article): ?>
|
||||
<article class="article-card">
|
||||
<!-- Date -->
|
||||
<?php if ($article->date()->isNotEmpty()): ?>
|
||||
<time class="article-card__date" datetime="<?= $article->date()->toDate('Y-m-d') ?>">
|
||||
<?= $article->date()->toDate('d/m/Y') ?>
|
||||
</time>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="article-card__content">
|
||||
<h2 class="article-card__title">
|
||||
<a href="<?= $article->url() ?>"><?= $article->title() ?></a>
|
||||
</h2>
|
||||
|
||||
<?php if ($article->intro()->isNotEmpty()): ?>
|
||||
<p class="article-card__intro"><?= $article->intro()->excerpt(200) ?></p>
|
||||
<?php endif ?>
|
||||
|
||||
<a href="<?= $article->url() ?>" class="article-card__link">
|
||||
Lire la suite →
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Author -->
|
||||
<div class="article-card__author">
|
||||
<?php if ($photo = $article->author_photo()->toFile()): ?>
|
||||
<img src="<?= $photo->url() ?>" alt="<?= $article->author_name() ?>" class="article-card__author-photo">
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($article->author_name()->isNotEmpty()): ?>
|
||||
<span class="article-card__author-name"><?= $article->author_name() ?></span>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<!-- Cover Image -->
|
||||
<?php if ($cover = $article->cover()->toFile()): ?>
|
||||
<div class="article-card__cover">
|
||||
<img src="<?= $cover->url() ?>" alt="<?= $article->title() ?>">
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</article>
|
||||
<?php endforeach ?>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<?php snippet('footer') ?>
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
$specificData = [
|
||||
'body' => $page->body()->toBlocks()
|
||||
];
|
||||
|
||||
$pageData = array_merge($genericData, $specificData);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($pageData);
|
||||
|
|
@ -1,2 +1 @@
|
|||
<?php snippet('header') ?>
|
||||
<?php snippet('footer') ?>
|
||||
<h1><?= $page->title() ?></h1>
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
$specificData = [
|
||||
'intro' => [
|
||||
'title' => $page->intro_title()->value(),
|
||||
'text' => $page->intro_text()->value()
|
||||
],
|
||||
'sections' => $page->expertise_sections()->toStructure()->map(function($section) {
|
||||
return [
|
||||
'title' => $section->title()->value(),
|
||||
'icon' => $section->icon()->value(),
|
||||
'content' => $section->content()->toBlocks()
|
||||
];
|
||||
})->values(),
|
||||
'objective' => [
|
||||
'title' => $page->objective_title()->value(),
|
||||
'text' => $page->objective_text()->value()
|
||||
]
|
||||
];
|
||||
|
||||
$pageData = array_merge($genericData, $specificData);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($pageData);
|
||||
|
|
@ -1,2 +1,36 @@
|
|||
<?php snippet('header') ?>
|
||||
|
||||
<main class="expertise">
|
||||
<!-- Intro Section -->
|
||||
<section class="expertise__intro">
|
||||
<h1 class="expertise__title"><?= $page->intro_title() ?></h1>
|
||||
|
||||
<?php if ($page->intro_text()->isNotEmpty()): ?>
|
||||
<p class="expertise__text"><?= $page->intro_text() ?></p>
|
||||
<?php endif ?>
|
||||
</section>
|
||||
|
||||
<!-- Expertise Sections -->
|
||||
<?php if ($page->expertise_sections()->isNotEmpty()): ?>
|
||||
<div class="expertise__sections">
|
||||
<?php foreach ($page->expertise_sections()->toStructure() as $section): ?>
|
||||
<section class="expertise-section expertise-section--<?= $section->icon() ?>">
|
||||
<h2 class="expertise-section__title"><?= $section->title() ?></h2>
|
||||
<div class="expertise-section__content">
|
||||
<?= $section->content()->toBlocks() ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Objective Section -->
|
||||
<?php if ($page->objective_text()->isNotEmpty()): ?>
|
||||
<section class="expertise__objective">
|
||||
<h2 class="expertise__objective-title"><?= $page->objective_title() ?></h2>
|
||||
<p class="expertise__objective-text"><?= $page->objective_text() ?></p>
|
||||
</section>
|
||||
<?php endif ?>
|
||||
</main>
|
||||
|
||||
<?php snippet('footer') ?>
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
<?php
|
||||
|
||||
$specificData = [
|
||||
'description' => $page->description()->value(),
|
||||
'rules' => $page->rules()->toBlocks(),
|
||||
'game_status' => $page->game_status()->value(),
|
||||
'is_embedded' => $page->is_embedded()->toBool(),
|
||||
'play_link' => $page->play_link()->value(),
|
||||
'cover' => $page->cover()->toFile()?->url(),
|
||||
'parent_url' => $page->parent()->url()
|
||||
];
|
||||
|
||||
$pageData = array_merge($genericData, $specificData);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($pageData);
|
||||
|
|
@ -1,2 +1,58 @@
|
|||
<?php snippet('header') ?>
|
||||
|
||||
<main class="game">
|
||||
<article class="game__content">
|
||||
<!-- Info -->
|
||||
<div class="game__info">
|
||||
<h1 class="game__title"><?= $page->title() ?></h1>
|
||||
|
||||
<?php if ($page->description()->isNotEmpty()): ?>
|
||||
<p class="game__description"><?= $page->description() ?></p>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Rules -->
|
||||
<?php if ($page->rules()->isNotEmpty()): ?>
|
||||
<div class="game__rules">
|
||||
<?= $page->rules()->toBlocks() ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Status Button -->
|
||||
<?php if ($page->game_status()->value() !== 'available'): ?>
|
||||
<div class="game__status">
|
||||
<span class="btn btn--disabled">
|
||||
<?= $page->game_status()->value() === 'coming_soon' ? 'Bientôt disponible' : 'En maintenance' ?>
|
||||
</span>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<!-- Game Area -->
|
||||
<div class="game__area">
|
||||
<?php if ($page->game_status()->value() === 'available'): ?>
|
||||
<?php if ($page->is_embedded()->toBool() && $page->play_link()->isNotEmpty()): ?>
|
||||
<iframe src="<?= $page->play_link() ?>" class="game__iframe" frameborder="0"></iframe>
|
||||
<?php elseif ($page->play_link()->isNotEmpty()): ?>
|
||||
<a href="<?= $page->play_link() ?>" class="game__external-link btn btn--large" target="_blank">
|
||||
Jouer maintenant
|
||||
</a>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($cover = $page->cover()->toFile()): ?>
|
||||
<div class="game__cover">
|
||||
<img src="<?= $cover->url() ?>" alt="<?= $page->title() ?>">
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- Back Navigation -->
|
||||
<nav class="game__nav">
|
||||
<a href="<?= $page->parent()->url() ?>" class="game__nav-back">
|
||||
← Retour aux jeux
|
||||
</a>
|
||||
</nav>
|
||||
</main>
|
||||
|
||||
<?php snippet('footer') ?>
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
$specificData = [
|
||||
'hero' => [
|
||||
'title' => $page->hero_title()->value(),
|
||||
'title_highlight' => $page->hero_title_highlight()->value(),
|
||||
'subtitle' => $page->hero_subtitle()->value(),
|
||||
'cta_text' => $page->hero_cta_text()->value(),
|
||||
'cta_link' => $page->hero_cta_link()->toPage()?->url() ?? '#',
|
||||
'image' => $page->hero_image()->toFile()?->url()
|
||||
],
|
||||
'background_video' => $page->background_video()->toFile()?->url(),
|
||||
'floating_bubbles' => $page->floating_bubbles()->toStructure()->map(function($bubble) {
|
||||
return [
|
||||
'text' => $bubble->text()->value(),
|
||||
'position' => $bubble->position()->value()
|
||||
];
|
||||
})->values()
|
||||
];
|
||||
|
||||
$pageData = array_merge($genericData, $specificData);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($pageData);
|
||||
|
|
@ -1,2 +1,49 @@
|
|||
<?php snippet('header') ?>
|
||||
|
||||
<main class="home">
|
||||
<!-- Hero Section -->
|
||||
<section class="hero">
|
||||
<div class="hero__content">
|
||||
<h1 class="hero__title">
|
||||
<?php
|
||||
$title = $page->hero_title()->value();
|
||||
$highlight = $page->hero_title_highlight()->value();
|
||||
if ($highlight) {
|
||||
echo str_replace($highlight, '<span class="highlight">' . $highlight . '</span>', $title);
|
||||
} else {
|
||||
echo $title;
|
||||
}
|
||||
?>
|
||||
</h1>
|
||||
|
||||
<?php if ($page->hero_subtitle()->isNotEmpty()): ?>
|
||||
<p class="hero__subtitle"><?= $page->hero_subtitle() ?></p>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($page->hero_cta_text()->isNotEmpty()): ?>
|
||||
<a href="<?= $page->hero_cta_link()->toPage()?->url() ?? '#' ?>" class="hero__cta btn">
|
||||
<?= $page->hero_cta_text() ?>
|
||||
</a>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<?php if ($hero = $page->hero_image()->toFile()): ?>
|
||||
<div class="hero__image">
|
||||
<img src="<?= $hero->url() ?>" alt="<?= $page->hero_title() ?>">
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Floating Bubbles -->
|
||||
<?php if ($page->floating_bubbles()->isNotEmpty()): ?>
|
||||
<div class="hero__bubbles">
|
||||
<?php foreach ($page->floating_bubbles()->toStructure() as $bubble): ?>
|
||||
<div class="bubble bubble--<?= $bubble->position() ?>">
|
||||
<?= $bubble->text() ?>
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<?php snippet('footer') ?>
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
<?php
|
||||
|
||||
$specificData = [
|
||||
'intro' => [
|
||||
'title' => $page->intro_title()->value(),
|
||||
'text' => $page->intro_text()->value()
|
||||
],
|
||||
'games' => $page->children()->listed()->map(function($game) {
|
||||
$badgeValue = $game->badge()->value();
|
||||
$badgeLabel = 'none';
|
||||
if ($badgeValue === 'new') {
|
||||
$badgeLabel = 'NEW';
|
||||
} elseif ($badgeValue === 'coming_soon') {
|
||||
$badgeLabel = 'INCOMING';
|
||||
}
|
||||
|
||||
return [
|
||||
'title' => $game->title()->value(),
|
||||
'slug' => $game->slug(),
|
||||
'url' => $game->url(),
|
||||
'description' => $game->description()->value(),
|
||||
'cover' => $game->cover()->toFile()?->url(),
|
||||
'badge' => $badgeValue,
|
||||
'badge_label' => $badgeLabel,
|
||||
'game_status' => $game->game_status()->value()
|
||||
];
|
||||
})->values()
|
||||
];
|
||||
|
||||
$pageData = array_merge($genericData, $specificData);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($pageData);
|
||||
|
|
@ -1,2 +1,57 @@
|
|||
<?php snippet('header') ?>
|
||||
|
||||
<main class="jouer">
|
||||
<!-- Intro Section -->
|
||||
<section class="jouer__intro">
|
||||
<?php if ($page->intro_title()->isNotEmpty()): ?>
|
||||
<h1 class="jouer__title"><?= $page->intro_title() ?></h1>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($page->intro_text()->isNotEmpty()): ?>
|
||||
<p class="jouer__text"><?= $page->intro_text() ?></p>
|
||||
<?php endif ?>
|
||||
</section>
|
||||
|
||||
<!-- Games List -->
|
||||
<section class="jouer__games">
|
||||
<?php foreach ($page->children()->listed() as $game): ?>
|
||||
<article class="game-card">
|
||||
<!-- Badge -->
|
||||
<?php if ($game->badge()->isNotEmpty() && $game->badge()->value() !== 'none'): ?>
|
||||
<span class="game-card__badge game-card__badge--<?= $game->badge() ?>">
|
||||
<?= $game->badge()->value() === 'new' ? 'NEW' : ($game->badge()->value() === 'coming_soon' ? 'INCOMING' : $game->badge()) ?>
|
||||
</span>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Cover -->
|
||||
<?php if ($cover = $game->cover()->toFile()): ?>
|
||||
<div class="game-card__cover">
|
||||
<img src="<?= $cover->url() ?>" alt="<?= $game->title() ?>">
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Info -->
|
||||
<div class="game-card__info">
|
||||
<h2 class="game-card__title"><?= $game->title() ?></h2>
|
||||
|
||||
<?php if ($game->description()->isNotEmpty()): ?>
|
||||
<p class="game-card__description"><?= $game->description() ?></p>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Play Button -->
|
||||
<?php if ($game->game_status()->value() === 'available'): ?>
|
||||
<a href="<?= $game->url() ?>" class="game-card__play btn">
|
||||
Jouer
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<span class="game-card__status btn btn--disabled">
|
||||
Bientôt disponible
|
||||
</span>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach ?>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<?php snippet('footer') ?>
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
$specificData = [
|
||||
'intro' => [
|
||||
'title' => $page->intro_title()->value(),
|
||||
'text' => $page->intro_text()->value()
|
||||
],
|
||||
'projects' => $page->children()->listed()->map(function($project) {
|
||||
return [
|
||||
'title' => $project->title()->value(),
|
||||
'slug' => $project->slug(),
|
||||
'url' => $project->url(),
|
||||
'tagline' => $project->tagline()->value(),
|
||||
'description' => $project->description()->value(),
|
||||
'cover' => $project->cover()->toFile()?->url(),
|
||||
'cover_thumb' => $project->cover()->toFile()?->thumb(['width' => 100])->url(),
|
||||
'gallery' => $project->files()->filterBy('template', 'image')->limit(5)->map(function($img) {
|
||||
return $img->url();
|
||||
})->values(),
|
||||
'impact' => $project->impact()->split(','),
|
||||
'category' => $project->category()->value(),
|
||||
'platforms' => $project->platforms()->split(','),
|
||||
'apple_link' => $project->apple_link()->value(),
|
||||
'android_link' => $project->android_link()->value()
|
||||
];
|
||||
})->values()
|
||||
];
|
||||
|
||||
$pageData = array_merge($genericData, $specificData);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($pageData);
|
||||
|
|
@ -1,2 +1,109 @@
|
|||
<?php snippet('header') ?>
|
||||
|
||||
<main class="portfolio">
|
||||
<!-- Intro Section -->
|
||||
<section class="portfolio__intro">
|
||||
<?php if ($page->intro_title()->isNotEmpty()): ?>
|
||||
<h1 class="portfolio__title"><?= $page->intro_title() ?></h1>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($page->intro_text()->isNotEmpty()): ?>
|
||||
<p class="portfolio__text"><?= $page->intro_text() ?></p>
|
||||
<?php endif ?>
|
||||
</section>
|
||||
|
||||
<!-- Projects Grid -->
|
||||
<section class="portfolio__projects">
|
||||
<?php
|
||||
$projects = $page->children()->listed();
|
||||
$total = $projects->count();
|
||||
$index = 0;
|
||||
?>
|
||||
|
||||
<?php foreach ($projects as $project): ?>
|
||||
<?php $index++ ?>
|
||||
<article class="project-card" data-index="<?= $index ?>">
|
||||
<!-- Project Gallery -->
|
||||
<div class="project-card__gallery">
|
||||
<?php if ($cover = $project->cover()->toFile()): ?>
|
||||
<img src="<?= $cover->url() ?>" alt="<?= $project->title() ?>" class="project-card__cover">
|
||||
<?php endif ?>
|
||||
|
||||
<?php foreach ($project->files()->filterBy('template', 'image')->limit(5) as $image): ?>
|
||||
<img src="<?= $image->url() ?>" alt="" class="project-card__image">
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
|
||||
<!-- Project Info -->
|
||||
<div class="project-card__info">
|
||||
<h2 class="project-card__title"><?= $project->title() ?></h2>
|
||||
|
||||
<?php if ($project->tagline()->isNotEmpty()): ?>
|
||||
<p class="project-card__tagline"><?= $project->tagline() ?></p>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($project->description()->isNotEmpty()): ?>
|
||||
<p class="project-card__description"><?= $project->description() ?></p>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Meta -->
|
||||
<div class="project-card__meta">
|
||||
<?php if ($project->impact()->isNotEmpty()): ?>
|
||||
<div class="project-card__impact">
|
||||
<span class="label">Impact:</span>
|
||||
<?= $project->impact()->join(', ') ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($project->category()->isNotEmpty()): ?>
|
||||
<div class="project-card__category">
|
||||
<span class="label">Catégorie:</span>
|
||||
<?= $project->category()->value() ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($project->platforms()->isNotEmpty()): ?>
|
||||
<div class="project-card__platforms">
|
||||
<span class="label">Plateformes:</span>
|
||||
<?= $project->platforms()->join(' / ') ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<!-- Links -->
|
||||
<div class="project-card__links">
|
||||
<?php if ($project->apple_link()->isNotEmpty()): ?>
|
||||
<a href="<?= $project->apple_link() ?>" class="btn btn--apple" target="_blank">
|
||||
Apple
|
||||
</a>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($project->android_link()->isNotEmpty()): ?>
|
||||
<a href="<?= $project->android_link() ?>" class="btn btn--android" target="_blank">
|
||||
Android
|
||||
</a>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Counter -->
|
||||
<div class="project-card__counter">
|
||||
<?= str_pad($index, 2, '0', STR_PAD_LEFT) ?>/<?= str_pad($total, 2, '0', STR_PAD_LEFT) ?>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach ?>
|
||||
</section>
|
||||
|
||||
<!-- Thumbnails Navigation -->
|
||||
<nav class="portfolio__thumbnails">
|
||||
<?php foreach ($projects as $project): ?>
|
||||
<a href="#<?= $project->slug() ?>" class="portfolio__thumbnail">
|
||||
<?php if ($cover = $project->cover()->toFile()): ?>
|
||||
<img src="<?= $cover->thumb(['width' => 100])->url() ?>" alt="<?= $project->title() ?>">
|
||||
<?php endif ?>
|
||||
</a>
|
||||
<?php endforeach ?>
|
||||
</nav>
|
||||
</main>
|
||||
|
||||
<?php snippet('footer') ?>
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
|
||||
$specificData = [
|
||||
'tagline' => $page->tagline()->value(),
|
||||
'description' => $page->description()->kt(),
|
||||
'cover' => $page->cover()->toFile()?->url(),
|
||||
'gallery' => $page->files()->filterBy('template', 'image')->map(function($img) {
|
||||
return $img->url();
|
||||
})->values(),
|
||||
'impact' => $page->impact()->split(','),
|
||||
'category' => $page->category()->value(),
|
||||
'platforms' => $page->platforms()->split(','),
|
||||
'client_name' => $page->client_name()->value(),
|
||||
'apple_link' => $page->apple_link()->value(),
|
||||
'android_link' => $page->android_link()->value(),
|
||||
'web_link' => $page->web_link()->value(),
|
||||
'prev' => $page->prev() ? [
|
||||
'title' => $page->prev()->title()->value(),
|
||||
'url' => $page->prev()->url()
|
||||
] : null,
|
||||
'next' => $page->next() ? [
|
||||
'title' => $page->next()->title()->value(),
|
||||
'url' => $page->next()->url()
|
||||
] : null,
|
||||
'parent_url' => $page->parent()->url()
|
||||
];
|
||||
|
||||
$pageData = array_merge($genericData, $specificData);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($pageData);
|
||||
|
|
@ -1,2 +1,104 @@
|
|||
<?php snippet('header') ?>
|
||||
|
||||
<main class="project">
|
||||
<article class="project__content">
|
||||
<!-- Gallery -->
|
||||
<div class="project__gallery">
|
||||
<?php if ($cover = $page->cover()->toFile()): ?>
|
||||
<img src="<?= $cover->url() ?>" alt="<?= $page->title() ?>" class="project__cover">
|
||||
<?php endif ?>
|
||||
|
||||
<?php foreach ($page->files()->filterBy('template', 'image') as $image): ?>
|
||||
<img src="<?= $image->url() ?>" alt="" class="project__image">
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
|
||||
<!-- Info -->
|
||||
<div class="project__info">
|
||||
<h1 class="project__title"><?= $page->title() ?></h1>
|
||||
|
||||
<?php if ($page->tagline()->isNotEmpty()): ?>
|
||||
<p class="project__tagline"><?= $page->tagline() ?></p>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($page->description()->isNotEmpty()): ?>
|
||||
<div class="project__description">
|
||||
<?= $page->description()->kt() ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<!-- Meta -->
|
||||
<div class="project__meta">
|
||||
<?php if ($page->impact()->isNotEmpty()): ?>
|
||||
<div class="project__impact">
|
||||
<span class="label">Impact:</span>
|
||||
<?= $page->impact()->join(', ') ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($page->category()->isNotEmpty()): ?>
|
||||
<div class="project__category">
|
||||
<span class="label">Catégorie:</span>
|
||||
<?= $page->category()->value() ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($page->platforms()->isNotEmpty()): ?>
|
||||
<div class="project__platforms">
|
||||
<span class="label">Plateformes:</span>
|
||||
<?= $page->platforms()->join(' / ') ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($page->client_name()->isNotEmpty()): ?>
|
||||
<div class="project__client">
|
||||
<span class="label">Client:</span>
|
||||
<?= $page->client_name() ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<!-- Links -->
|
||||
<div class="project__links">
|
||||
<?php if ($page->apple_link()->isNotEmpty()): ?>
|
||||
<a href="<?= $page->apple_link() ?>" class="btn btn--apple" target="_blank">
|
||||
App Store
|
||||
</a>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($page->android_link()->isNotEmpty()): ?>
|
||||
<a href="<?= $page->android_link() ?>" class="btn btn--android" target="_blank">
|
||||
Play Store
|
||||
</a>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($page->web_link()->isNotEmpty()): ?>
|
||||
<a href="<?= $page->web_link() ?>" class="btn btn--web" target="_blank">
|
||||
Voir le site
|
||||
</a>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- Navigation -->
|
||||
<nav class="project__nav">
|
||||
<?php if ($prev = $page->prev()): ?>
|
||||
<a href="<?= $prev->url() ?>" class="project__nav-prev">
|
||||
← <?= $prev->title() ?>
|
||||
</a>
|
||||
<?php endif ?>
|
||||
|
||||
<a href="<?= $page->parent()->url() ?>" class="project__nav-back">
|
||||
Tous les projets
|
||||
</a>
|
||||
|
||||
<?php if ($next = $page->next()): ?>
|
||||
<a href="<?= $next->url() ?>" class="project__nav-next">
|
||||
<?= $next->title() ?> →
|
||||
</a>
|
||||
<?php endif ?>
|
||||
</nav>
|
||||
</main>
|
||||
|
||||
<?php snippet('footer') ?>
|
||||
|
|
|
|||
|
|
@ -1,86 +0,0 @@
|
|||
<script>
|
||||
import { page } from '@state/page.svelte'
|
||||
|
||||
import Header from '@components/layout/Header.svelte'
|
||||
import Footer from '@components/layout/Footer.svelte'
|
||||
import Cursor from '@components/layout/Cursor.svelte'
|
||||
|
||||
import Home from '@views/Home.svelte'
|
||||
import About from '@views/About.svelte'
|
||||
import Expertise from '@views/Expertise.svelte'
|
||||
import Portfolio from '@views/Portfolio.svelte'
|
||||
import Project from '@views/Project.svelte'
|
||||
import Jouer from '@views/Jouer.svelte'
|
||||
import Game from '@views/Game.svelte'
|
||||
import Blog from '@views/Blog.svelte'
|
||||
import Article from '@views/Article.svelte'
|
||||
import Default from '@views/Default.svelte'
|
||||
|
||||
const templates = {
|
||||
'home': Home,
|
||||
'about': About,
|
||||
'expertise': Expertise,
|
||||
'portfolio': Portfolio,
|
||||
'project': Project,
|
||||
'jouer': Jouer,
|
||||
'game': Game,
|
||||
'blog': Blog,
|
||||
'article': Article,
|
||||
'default': Default
|
||||
}
|
||||
|
||||
const template = $derived(page.template || 'default')
|
||||
const view = $derived(templates[template] || Default)
|
||||
const pageData = $derived(page.data)
|
||||
const showFooter = $derived(template !== 'home')
|
||||
</script>
|
||||
|
||||
<div class="app">
|
||||
<Cursor />
|
||||
<Header />
|
||||
|
||||
<main class="main">
|
||||
{#if pageData && view}
|
||||
<view data={pageData} />
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
{#if showFooter}
|
||||
<Footer />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:global(*) {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:global(body) {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
background: #000;
|
||||
color: #fff;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.app {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
:global(a) {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
:global(img) {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
let cursorX = 0
|
||||
let cursorY = 0
|
||||
let outlineX = 0
|
||||
let outlineY = 0
|
||||
let rafId
|
||||
|
||||
onMount(() => {
|
||||
const handleMouseMove = (e) => {
|
||||
cursorX = e.clientX
|
||||
cursorY = e.clientY
|
||||
}
|
||||
|
||||
const animate = () => {
|
||||
outlineX += (cursorX - outlineX) * 0.2
|
||||
outlineY += (cursorY - outlineY) * 0.2
|
||||
rafId = requestAnimationFrame(animate)
|
||||
}
|
||||
|
||||
window.addEventListener('mousemove', handleMouseMove)
|
||||
animate()
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('mousemove', handleMouseMove)
|
||||
if (rafId) cancelAnimationFrame(rafId)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="cursor" style="transform: translate({cursorX}px, {cursorY}px)"></div>
|
||||
<div class="cursor-outline" style="transform: translate({outlineX}px, {outlineY}px)"></div>
|
||||
|
||||
<style>
|
||||
.cursor,
|
||||
.cursor-outline {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.cursor {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: #04fea0;
|
||||
border-radius: 50%;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.cursor-outline {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 2px solid #04fea0;
|
||||
border-radius: 50%;
|
||||
transform-origin: center;
|
||||
margin: -16px 0 0 -16px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.cursor,
|
||||
.cursor-outline {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
<script>
|
||||
import { site } from '@state/site.svelte'
|
||||
|
||||
const siteTitle = $derived(site.title || 'World Game')
|
||||
const currentYear = $derived(new Date().getFullYear())
|
||||
</script>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="footer__container">
|
||||
<div class="footer__brand">
|
||||
<p class="footer__title">{siteTitle}</p>
|
||||
<p class="footer__tagline">Play to Engage</p>
|
||||
</div>
|
||||
|
||||
<div class="footer__copyright">
|
||||
<p>© {currentYear} {siteTitle}. Tous droits réservés.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
.footer {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
padding: 3rem 2rem 2rem;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.footer__container {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.footer__brand {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.footer__title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 0.5rem;
|
||||
}
|
||||
|
||||
.footer__tagline {
|
||||
color: #04fea0;
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.footer__copyright {
|
||||
font-size: 0.85rem;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.footer__copyright p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.footer__container {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer__copyright {
|
||||
order: 2;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,280 +0,0 @@
|
|||
<script>
|
||||
import { navigation } from '@state/navigation.svelte'
|
||||
import { locale } from '@state/locale.svelte'
|
||||
import { page } from '@state/page.svelte'
|
||||
import { navigateTo } from '@state/router'
|
||||
|
||||
const isMenuOpen = $derived(navigation.isMenuOpen)
|
||||
const currentLang = $derived(locale.current)
|
||||
const currentPage = $derived(page.template || 'home')
|
||||
|
||||
const translations = {
|
||||
expertise: { fr: 'EXPERTISE', en: 'EXPERTISE' },
|
||||
games: { fr: 'GAMES', en: 'GAMES' },
|
||||
play: { fr: 'PLAY', en: 'PLAY' },
|
||||
about: { fr: 'À PROPOS', en: 'ABOUT' },
|
||||
blog: { fr: 'BLOG', en: 'BLOG' }
|
||||
}
|
||||
|
||||
function t(key) {
|
||||
return translations[key]?.[currentLang] || translations[key]?.fr || key
|
||||
}
|
||||
|
||||
function handleNav(path) {
|
||||
navigateTo(path)
|
||||
}
|
||||
|
||||
function toggleMenu() {
|
||||
navigation.toggleMenu()
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="navbar">
|
||||
<div
|
||||
class="clickable"
|
||||
style="
|
||||
z-index: 60;
|
||||
position: absolute;
|
||||
float: left;
|
||||
left: 5vh;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
"
|
||||
onclick={() => handleNav('/')}
|
||||
onkeypress={(e) => e.key === 'Enter' && handleNav('/')}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<img
|
||||
src="/assets/img/GIF_world_game_planete.gif"
|
||||
alt="World Game"
|
||||
class="clickable wg-logo"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="navbar-item clickable"
|
||||
class:active={currentPage === 'expertise'}
|
||||
style="visibility: {isMenuOpen ? 'hidden' : 'visible'};"
|
||||
onclick={() => handleNav('/expertise')}
|
||||
onkeypress={(e) => e.key === 'Enter' && handleNav('/expertise')}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
{t('expertise')}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="navbar-item clickable"
|
||||
class:active={currentPage === 'portfolio'}
|
||||
style="visibility: {isMenuOpen ? 'hidden' : 'visible'};"
|
||||
onclick={() => handleNav('/portfolio')}
|
||||
onkeypress={(e) => e.key === 'Enter' && handleNav('/portfolio')}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
{t('games')}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="navbar-item clickable"
|
||||
class:active={currentPage === 'jouer'}
|
||||
style="visibility: {isMenuOpen ? 'hidden' : 'visible'};"
|
||||
onclick={() => handleNav('/jouer')}
|
||||
onkeypress={(e) => e.key === 'Enter' && handleNav('/jouer')}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
{t('play')}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="navbar-item clickable"
|
||||
class:active={currentPage === 'about'}
|
||||
style="visibility: {isMenuOpen ? 'hidden' : 'visible'};"
|
||||
onclick={() => handleNav('/a-propos')}
|
||||
onkeypress={(e) => e.key === 'Enter' && handleNav('/a-propos')}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
{t('about')}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="navbar-item clickable"
|
||||
class:active={currentPage === 'blog' || currentPage === 'article'}
|
||||
style="visibility: {isMenuOpen ? 'hidden' : 'visible'};"
|
||||
onclick={() => handleNav('/blog')}
|
||||
onkeypress={(e) => e.key === 'Enter' && handleNav('/blog')}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
{t('blog')}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="clickable"
|
||||
style="
|
||||
z-index: 60;
|
||||
position: absolute;
|
||||
float: right;
|
||||
right: 5vh;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
"
|
||||
onclick={toggleMenu}
|
||||
onkeypress={(e) => e.key === 'Enter' && toggleMenu()}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
width="50"
|
||||
height="50"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
style="height: 4.5vh; min-height: 36px;"
|
||||
>
|
||||
<circle
|
||||
cx="7"
|
||||
cy="7"
|
||||
r="2"
|
||||
fill="white"
|
||||
style="
|
||||
transform: {isMenuOpen ? 'translate(5px, 5px) scale(0.7)' : 'translate(0px, 0px) scale(1)'};
|
||||
transform-origin: center;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
"
|
||||
/>
|
||||
|
||||
<circle
|
||||
cx="17"
|
||||
cy="7"
|
||||
r="2"
|
||||
fill="white"
|
||||
style="
|
||||
transform: {isMenuOpen ? 'translate(-5px, 5px) scale(0.7)' : 'translate(0px, 0px) scale(1)'};
|
||||
transform-origin: center;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
"
|
||||
/>
|
||||
|
||||
<circle
|
||||
cx="7"
|
||||
cy="17"
|
||||
r="2"
|
||||
fill="white"
|
||||
style="
|
||||
transform: {isMenuOpen ? 'translate(5px, -5px) scale(0.7)' : 'translate(0px, 0px) scale(1)'};
|
||||
transform-origin: center;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
"
|
||||
/>
|
||||
|
||||
<circle
|
||||
cx="17"
|
||||
cy="17"
|
||||
r="2"
|
||||
fill="white"
|
||||
style="
|
||||
transform: {isMenuOpen ? 'translate(-5px, -5px) scale(0.7)' : 'translate(0px, 0px) scale(1)'};
|
||||
transform-origin: center;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
"
|
||||
/>
|
||||
|
||||
<line
|
||||
x1="9"
|
||||
y1="9"
|
||||
x2="15"
|
||||
y2="15"
|
||||
stroke="white"
|
||||
stroke-width="2.5"
|
||||
stroke-linecap="round"
|
||||
style="
|
||||
opacity: {isMenuOpen ? 1 : 0};
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
transition-delay: {isMenuOpen ? '0.1s' : '0s'};
|
||||
"
|
||||
/>
|
||||
<line
|
||||
x1="15"
|
||||
y1="9"
|
||||
x2="9"
|
||||
y2="15"
|
||||
stroke="white"
|
||||
stroke-width="2.5"
|
||||
stroke-linecap="round"
|
||||
style="
|
||||
opacity: {isMenuOpen ? 1 : 0};
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
transition-delay: {isMenuOpen ? '0.1s' : '0s'};
|
||||
"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.navbar {
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-self: center;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 50;
|
||||
font-family: "Danzza";
|
||||
font-size: var(--font-size-paragraph);
|
||||
font-weight: normal;
|
||||
color: white;
|
||||
text-align: center !important;
|
||||
text-transform: uppercase;
|
||||
padding: 2vh 0 2vh 0;
|
||||
backdrop-filter: blur(0px);
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.navbar-item {
|
||||
display: inline-block;
|
||||
padding: 1vmax 2vmax;
|
||||
font-weight: bold;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
color: white;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.navbar-item.active {
|
||||
color: #04fea0;
|
||||
}
|
||||
|
||||
.navbar-item:hover {
|
||||
color: #04fea0;
|
||||
}
|
||||
|
||||
.wg-logo {
|
||||
height: 4.8vh;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 700px) {
|
||||
.navbar-item {
|
||||
font-size: var(--font-size-paragraph-mobile);
|
||||
padding: 1vmax 1.5vmax;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 701px) and (max-width: 912px) {
|
||||
.navbar-item {
|
||||
font-size: var(--font-size-paragraph-tablet);
|
||||
padding: 1vmax 1.8vmax;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
<script>
|
||||
let { variant = 'primary' // primary, secondary, outline } = $props()
|
||||
let { size = 'medium' // small, medium, large } = $props()
|
||||
let { disabled = false } = $props()
|
||||
let { href = null } = $props()
|
||||
</script>
|
||||
|
||||
{#if href}
|
||||
<a
|
||||
{href}
|
||||
class="btn btn--{variant} btn--{size}"
|
||||
class:disabled
|
||||
on:click
|
||||
>
|
||||
<slot />
|
||||
</a>
|
||||
{:else}
|
||||
<button
|
||||
class="btn btn--{variant} btn--{size}"
|
||||
{disabled}
|
||||
on:click
|
||||
>
|
||||
<slot />
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem 2rem;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
border: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.btn--primary {
|
||||
background: #04fea0;
|
||||
color: #000;
|
||||
border-color: #04fea0;
|
||||
}
|
||||
|
||||
.btn--primary:hover {
|
||||
background: #03d98c;
|
||||
border-color: #03d98c;
|
||||
}
|
||||
|
||||
.btn--secondary {
|
||||
background: #000;
|
||||
color: #04fea0;
|
||||
border-color: #04fea0;
|
||||
}
|
||||
|
||||
.btn--secondary:hover {
|
||||
background: #04fea0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.btn--outline {
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
border-color: #fff;
|
||||
}
|
||||
|
||||
.btn--outline:hover {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.btn--small {
|
||||
padding: 0.5rem 1.5rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.btn--medium {
|
||||
padding: 0.75rem 2rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.btn--large {
|
||||
padding: 1rem 2.5rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.btn:disabled,
|
||||
.btn.disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
let { src } = $props()
|
||||
let { poster = '' } = $props()
|
||||
let { overlay = true } = $props()
|
||||
|
||||
let videoElement
|
||||
|
||||
onMount(() => {
|
||||
if (videoElement && src) {
|
||||
videoElement.play().catch(err => {
|
||||
console.log('Autoplay failed:', err)
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="video-background">
|
||||
{#if src}
|
||||
<video
|
||||
bind:this={videoElement}
|
||||
{poster}
|
||||
muted
|
||||
loop
|
||||
playsinline
|
||||
preload="metadata"
|
||||
class="video-background__video"
|
||||
>
|
||||
<source {src} type="video/mp4" />
|
||||
</video>
|
||||
{/if}
|
||||
|
||||
{#if overlay}
|
||||
<div class="video-background__overlay"></div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.video-background {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
overflow: hidden;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.video-background__video {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
width: auto;
|
||||
height: auto;
|
||||
transform: translate(-50%, -50%);
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.video-background__overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(0, 0, 0, 0.3),
|
||||
rgba(0, 0, 0, 0.7)
|
||||
);
|
||||
}
|
||||
</style>
|
||||
12
src/main.js
12
src/main.js
|
|
@ -1,12 +0,0 @@
|
|||
import './styles/index.css'
|
||||
import App from './App.svelte'
|
||||
import { mount } from 'svelte'
|
||||
import { initRouter } from './state/router'
|
||||
|
||||
initRouter()
|
||||
|
||||
const app = mount(App, {
|
||||
target: document.getElementById('app')
|
||||
})
|
||||
|
||||
export default app
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
import gsap from 'gsap'
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger)
|
||||
|
||||
/**
|
||||
* Fade in animation for page enter
|
||||
*/
|
||||
export function pageEnter(element, options = {}) {
|
||||
const defaults = {
|
||||
opacity: 0,
|
||||
y: 50,
|
||||
duration: 0.8,
|
||||
ease: 'power3.out'
|
||||
}
|
||||
|
||||
return gsap.from(element, { ...defaults, ...options })
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade out animation for page exit
|
||||
*/
|
||||
export function pageExit(element, options = {}) {
|
||||
const defaults = {
|
||||
opacity: 0,
|
||||
y: -50,
|
||||
duration: 0.5,
|
||||
ease: 'power3.in'
|
||||
}
|
||||
|
||||
return gsap.to(element, { ...defaults, ...options })
|
||||
}
|
||||
|
||||
/**
|
||||
* Carousel slide animation
|
||||
*/
|
||||
export function carouselSlide(element, offset, options = {}) {
|
||||
const defaults = {
|
||||
x: `-${offset}%`,
|
||||
duration: 0.8,
|
||||
ease: 'power2.inOut'
|
||||
}
|
||||
|
||||
return gsap.to(element, { ...defaults, ...options })
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll reveal animation
|
||||
*/
|
||||
export function scrollReveal(elements, options = {}) {
|
||||
const defaults = {
|
||||
scrollTrigger: {
|
||||
trigger: elements,
|
||||
start: 'top 80%',
|
||||
toggleActions: 'play none none none'
|
||||
},
|
||||
y: 50,
|
||||
opacity: 0,
|
||||
stagger: 0.1,
|
||||
duration: 0.8,
|
||||
ease: 'power3.out'
|
||||
}
|
||||
|
||||
return gsap.from(elements, { ...defaults, ...options })
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade in elements on scroll
|
||||
*/
|
||||
export function fadeInOnScroll(elements, options = {}) {
|
||||
const defaults = {
|
||||
scrollTrigger: {
|
||||
trigger: elements,
|
||||
start: 'top 80%'
|
||||
},
|
||||
opacity: 0,
|
||||
duration: 1,
|
||||
stagger: 0.2,
|
||||
ease: 'power2.out'
|
||||
}
|
||||
|
||||
return gsap.from(elements, { ...defaults, ...options })
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale animation
|
||||
*/
|
||||
export function scaleIn(element, options = {}) {
|
||||
const defaults = {
|
||||
scale: 0,
|
||||
duration: 0.5,
|
||||
ease: 'back.out(1.7)'
|
||||
}
|
||||
|
||||
return gsap.from(element, { ...defaults, ...options })
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup all ScrollTrigger instances
|
||||
*/
|
||||
export function cleanupScrollTriggers() {
|
||||
ScrollTrigger.getAll().forEach(trigger => trigger.kill())
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh ScrollTrigger (useful after content changes)
|
||||
*/
|
||||
export function refreshScrollTriggers() {
|
||||
ScrollTrigger.refresh()
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom cursor follow animation
|
||||
*/
|
||||
export function cursorFollow(cursorElement, outlineElement) {
|
||||
let cursorX = 0
|
||||
let cursorY = 0
|
||||
let outlineX = 0
|
||||
let outlineY = 0
|
||||
|
||||
const handleMouseMove = (e) => {
|
||||
cursorX = e.clientX
|
||||
cursorY = e.clientY
|
||||
}
|
||||
|
||||
const animate = () => {
|
||||
outlineX += (cursorX - outlineX) * 0.2
|
||||
outlineY += (cursorY - outlineY) * 0.2
|
||||
|
||||
gsap.set(cursorElement, { x: cursorX, y: cursorY })
|
||||
gsap.set(outlineElement, { x: outlineX, y: outlineY })
|
||||
|
||||
requestAnimationFrame(animate)
|
||||
}
|
||||
|
||||
window.addEventListener('mousemove', handleMouseMove)
|
||||
animate()
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('mousemove', handleMouseMove)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
let current = $state('fr')
|
||||
let languages = $state([])
|
||||
|
||||
export const locale = {
|
||||
get current() { return current },
|
||||
get languages() { return languages },
|
||||
|
||||
setLanguage: (code) => current = code,
|
||||
initialize: (language, langs) => {
|
||||
current = language
|
||||
languages = langs
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
let isMenuOpen = $state(false)
|
||||
let isLoading = $state(false)
|
||||
|
||||
export const navigation = {
|
||||
get isMenuOpen() { return isMenuOpen },
|
||||
get isLoading() { return isLoading },
|
||||
|
||||
toggleMenu: () => isMenuOpen = !isMenuOpen,
|
||||
openMenu: () => isMenuOpen = true,
|
||||
closeMenu: () => isMenuOpen = false,
|
||||
setLoading: (value) => isLoading = value
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
let data = $state(null)
|
||||
let template = $state(null)
|
||||
let url = $state(null)
|
||||
let loading = $state(false)
|
||||
let error = $state(null)
|
||||
|
||||
export const page = {
|
||||
get data() { return data },
|
||||
get template() { return template },
|
||||
get url() { return url },
|
||||
get loading() { return loading },
|
||||
get error() { return error },
|
||||
|
||||
set: (pageData) => {
|
||||
data = pageData.data
|
||||
template = pageData.template
|
||||
url = pageData.url
|
||||
loading = pageData.loading ?? false
|
||||
error = pageData.error ?? null
|
||||
},
|
||||
|
||||
setLoading: (value) => loading = value,
|
||||
setError: (err) => {
|
||||
error = err
|
||||
loading = false
|
||||
},
|
||||
|
||||
reset: () => {
|
||||
data = null
|
||||
template = null
|
||||
url = null
|
||||
loading = false
|
||||
error = null
|
||||
}
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
import navaid from "navaid";
|
||||
import { page } from "./page.svelte";
|
||||
import { navigation } from "./navigation.svelte";
|
||||
import { site } from "./site.svelte";
|
||||
import { locale } from "./locale.svelte";
|
||||
|
||||
export const router = navaid("/", () => {
|
||||
// Default handler
|
||||
});
|
||||
|
||||
async function loadPage(path) {
|
||||
navigation.setLoading(true);
|
||||
page.setLoading(true);
|
||||
|
||||
try {
|
||||
const response = await fetch(`${path}.json`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load page: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.site) {
|
||||
site.set(data.site);
|
||||
locale.initialize(data.site.language, data.site.languages);
|
||||
}
|
||||
|
||||
page.set({
|
||||
data,
|
||||
template: data.template || "default",
|
||||
url: path,
|
||||
loading: false,
|
||||
error: null,
|
||||
});
|
||||
|
||||
window.scrollTo(0, 0);
|
||||
} catch (error) {
|
||||
console.error("Failed to load page:", error);
|
||||
page.setError(error);
|
||||
} finally {
|
||||
navigation.setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Route handlers
|
||||
router
|
||||
.on("/", () => loadPage("/home"))
|
||||
.on("/expertise", () => loadPage("/expertise"))
|
||||
.on("/portfolio", () => loadPage("/portfolio"))
|
||||
.on("/portfolio/:slug", ({ slug }) => loadPage(`/portfolio/${slug}`))
|
||||
.on("/jouer", () => loadPage("/jouer"))
|
||||
.on("/jouer/:slug", ({ slug }) => loadPage(`/jouer/${slug}`))
|
||||
.on("/a-propos", () => loadPage("/a-propos"))
|
||||
.on("/blog", () => loadPage("/blog"))
|
||||
.on("/blog/:slug", ({ slug }) => loadPage(`/blog/${slug}`))
|
||||
.on("*", (params) => {
|
||||
// Fallback for other routes
|
||||
loadPage(window.location.pathname);
|
||||
});
|
||||
|
||||
export function initRouter() {
|
||||
// Load initial page data
|
||||
loadPage(window.location.pathname);
|
||||
|
||||
// Start listening to route changes
|
||||
router.listen();
|
||||
|
||||
// Intercept internal link clicks
|
||||
document.addEventListener("click", (e) => {
|
||||
const link = e.target.closest("a");
|
||||
if (!link) return;
|
||||
|
||||
const url = new URL(link.href, window.location.origin);
|
||||
|
||||
// Only intercept same-origin links without target attribute
|
||||
if (
|
||||
url.origin === window.location.origin &&
|
||||
!link.target &&
|
||||
!link.hasAttribute("download")
|
||||
) {
|
||||
e.preventDefault();
|
||||
navigateTo(url.pathname);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle browser back/forward
|
||||
window.addEventListener("popstate", () => {
|
||||
loadPage(window.location.pathname);
|
||||
});
|
||||
}
|
||||
|
||||
export function navigateTo(path) {
|
||||
window.history.pushState({}, "", path);
|
||||
loadPage(path);
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
let title = $state('')
|
||||
let url = $state('')
|
||||
let language = $state('fr')
|
||||
let languages = $state([])
|
||||
let logo = $state(null)
|
||||
let navigation = $state([])
|
||||
|
||||
export const site = {
|
||||
get title() { return title },
|
||||
get url() { return url },
|
||||
get language() { return language },
|
||||
get languages() { return languages },
|
||||
get logo() { return logo },
|
||||
get navigation() { return navigation },
|
||||
|
||||
set: (data) => {
|
||||
title = data.title || ''
|
||||
url = data.url || ''
|
||||
language = data.language || 'fr'
|
||||
languages = data.languages || []
|
||||
logo = data.logo || null
|
||||
navigation = data.navigation || []
|
||||
}
|
||||
}
|
||||
289
src/style.css
289
src/style.css
|
|
@ -1,289 +0,0 @@
|
|||
/* FONT SIZING SYSTEM - Consistent typography across the site */
|
||||
:root {
|
||||
/* Base font sizes for desktop */
|
||||
--font-size-paragraph: 18px;
|
||||
--font-size-paragraph-small: 16px;
|
||||
--font-size-subtitle: 20px;
|
||||
--font-size-title-section: 32px;
|
||||
--font-size-title-main: 48px;
|
||||
--font-size-title-hero: 96px;
|
||||
--font-size-button: 13px;
|
||||
--font-size-caption: 12px;
|
||||
|
||||
/* Mobile font sizes */
|
||||
--font-size-paragraph-mobile: 16px;
|
||||
--font-size-paragraph-small-mobile: 12px;
|
||||
--font-size-subtitle-mobile: 16px;
|
||||
--font-size-title-section-mobile: 24px;
|
||||
--font-size-title-main-mobile: 32px;
|
||||
--font-size-title-hero-mobile: 48px;
|
||||
--font-size-button-mobile: 11px;
|
||||
--font-size-caption-mobile: 10px;
|
||||
|
||||
/* Tablet font sizes */
|
||||
--font-size-paragraph-tablet: 16px;
|
||||
--font-size-paragraph-small-tablet: 14px;
|
||||
--font-size-subtitle-tablet: 18px;
|
||||
--font-size-title-section-tablet: 28px;
|
||||
--font-size-title-main-tablet: 40px;
|
||||
--font-size-title-hero-tablet: 64px;
|
||||
--font-size-button-tablet: 12px;
|
||||
--font-size-caption-tablet: 11px;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
min-height: 100vh;
|
||||
min-height: -webkit-fill-available;
|
||||
min-height: calc(var(--vh, 1vh) * 100);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Danzza Regular", "Danzza", -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
|
||||
"Droid Sans", "Helvetica Neue", sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
cursor: none;
|
||||
background: #000;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: none;
|
||||
}
|
||||
|
||||
/* Font faces */
|
||||
@font-face {
|
||||
font-family: "Terminal";
|
||||
font-weight: bold;
|
||||
src: local("terminal-grotesque"),
|
||||
url("/assets/fonts/terminal-grotesque.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Danzza";
|
||||
src: local("Danzza Regular"),
|
||||
url("/assets/fonts/Danzza-Regular.woff") format("woff"),
|
||||
url("/assets/fonts/Danzza-Regular.otf") format("opentype");
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Danzza Light";
|
||||
src: local("Danzza Light"),
|
||||
url("/assets/fonts/Danzza-Light.woff") format("woff"),
|
||||
url("/assets/fonts/Danzza-Light.otf") format("opentype");
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Danzza Medium";
|
||||
src: local("Danzza Medium"),
|
||||
url("/assets/fonts/Danzza-Medium.woff") format("woff"),
|
||||
url("/assets/fonts/Danzza-Medium.otf") format("opentype");
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Danzza Bold";
|
||||
src: local("Danzza Bold"),
|
||||
url("/assets/fonts/Danzza-Bold.woff") format("woff"),
|
||||
url("/assets/fonts/Danzza-Bold.otf") format("opentype");
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
.font-face-terminal {
|
||||
font-family: "Terminal";
|
||||
}
|
||||
|
||||
.font-face-danzza {
|
||||
font-family: "Danzza";
|
||||
}
|
||||
|
||||
.font-face-danzza-light {
|
||||
font-family: "Danzza Light";
|
||||
}
|
||||
|
||||
.font-face-danzza-medium {
|
||||
font-family: "Danzza Medium";
|
||||
}
|
||||
|
||||
.font-face-danzza-bold {
|
||||
font-family: "Danzza Bold";
|
||||
}
|
||||
|
||||
/* Golden Grid */
|
||||
.golden-grid {
|
||||
height: 100% !important;
|
||||
min-height: 100% !important;
|
||||
display: grid !important;
|
||||
position: relative;
|
||||
grid-template-rows: 1fr 1fr 2fr 4fr 2.66fr 5.33fr 5.33fr 4.33fr 2.83fr 3.5fr 3.5fr 2.83fr 4.33fr 5.33fr 5.33fr 2.66fr 4fr 2fr 1fr 1fr;
|
||||
grid-template-columns: 1fr 1fr 2fr 4fr 2.66fr 5.33fr 5.33fr 4.33fr 2.83fr 3.5fr 3.5fr 2.83fr 4.33fr 5.33fr 5.33fr 2.66fr 4fr 2fr 1fr 1fr;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.slide {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
/* Vertical Lines */
|
||||
.vertical-line {
|
||||
z-index: 1;
|
||||
border-left: 0.1px solid rgba(238, 238, 238, 0.2);
|
||||
height: 150%;
|
||||
}
|
||||
|
||||
.vertical-line-start {
|
||||
z-index: 1;
|
||||
border-left: 0.1px solid rgba(238, 238, 238, 0.2);
|
||||
grid-area: 1/6 / span 20 / span 1;
|
||||
height: 150%;
|
||||
}
|
||||
|
||||
.vertical-line-center {
|
||||
z-index: 1;
|
||||
border-left: 0.1px solid rgba(238, 238, 238, 0.2);
|
||||
grid-area: 1/11 / span 20 / span 1;
|
||||
height: 150%;
|
||||
}
|
||||
|
||||
.vertical-line-end {
|
||||
z-index: 1;
|
||||
border-left: 0.1px solid rgba(238, 238, 238, 0.2);
|
||||
grid-area: 1/16 / span 20 / span 1;
|
||||
height: 150%;
|
||||
}
|
||||
|
||||
/* Button */
|
||||
.button {
|
||||
width: 14vmax;
|
||||
min-width: 130px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: sticky;
|
||||
z-index: 1;
|
||||
padding: 12px 16px;
|
||||
transition: 0.5s ease-out;
|
||||
font-family: "Danzza Bold";
|
||||
background-color: #04fea0;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-position: left;
|
||||
background-color: transparent;
|
||||
outline: solid 2px #04fea0;
|
||||
}
|
||||
|
||||
.button p {
|
||||
color: black;
|
||||
margin: 0;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.button:hover p {
|
||||
color: #04fea0 !important;
|
||||
}
|
||||
|
||||
.earth-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-image: url('/assets/img/icon-earth-green.png');
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
margin-right: 8px;
|
||||
transition: filter 0.3s;
|
||||
}
|
||||
|
||||
.button:hover .earth-icon {
|
||||
filter: brightness(0) saturate(100%) invert(77%) sepia(82%) saturate(507%) hue-rotate(91deg) brightness(101%) contrast(97%);
|
||||
}
|
||||
|
||||
/* Clickable elements */
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Cursor */
|
||||
#cursor-dot,
|
||||
#cursor-dot-outline,
|
||||
#cursor-circle {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
z-index: 99999;
|
||||
transform: translate(-50%, -50%);
|
||||
transition: opacity 0.15s ease-in-out, transform 0.15s ease-in-out;
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#cursor-dot {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
#cursor-circle {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-width: 3px;
|
||||
border-style: solid;
|
||||
border-color: #04fea0;
|
||||
}
|
||||
|
||||
#cursor-dot-outline {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
@media (pointer: coarse) {
|
||||
#cursor-dot,
|
||||
#cursor-dot-outline,
|
||||
#cursor-circle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body,
|
||||
* {
|
||||
cursor: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* Selection */
|
||||
::selection {
|
||||
background: #04fea0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/* Scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #04fea0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #03d98c;
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
/* Button */
|
||||
.button {
|
||||
width: 14vmax;
|
||||
min-width: 130px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: sticky;
|
||||
z-index: 1;
|
||||
padding: 12px 16px;
|
||||
transition: 0.5s ease-out;
|
||||
font-family: "Danzza Bold";
|
||||
background-color: var(--color-primary);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-position: left;
|
||||
background-color: transparent;
|
||||
outline: solid 2px var(--color-primary);
|
||||
}
|
||||
|
||||
.button p {
|
||||
color: black;
|
||||
margin: 0;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.button:hover p {
|
||||
color: var(--color-primary) !important;
|
||||
}
|
||||
|
||||
.earth-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-image: url('/assets/img/icon-earth-green.png');
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
margin-right: 8px;
|
||||
transition: filter 0.3s;
|
||||
}
|
||||
|
||||
.button:hover .earth-icon {
|
||||
filter: brightness(0) saturate(100%) invert(77%) sepia(82%) saturate(507%) hue-rotate(91deg) brightness(101%) contrast(97%);
|
||||
}
|
||||
|
||||
/* Clickable elements */
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/* Custom Cursor */
|
||||
#cursor-dot,
|
||||
#cursor-dot-outline,
|
||||
#cursor-circle {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
z-index: 99999;
|
||||
transform: translate(-50%, -50%);
|
||||
transition: opacity 0.15s ease-in-out, transform 0.15s ease-in-out;
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#cursor-dot {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
#cursor-circle {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-width: 3px;
|
||||
border-style: solid;
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
#cursor-dot-outline {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
@media (pointer: coarse) {
|
||||
#cursor-dot,
|
||||
#cursor-dot-outline,
|
||||
#cursor-circle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
/* Font faces */
|
||||
@font-face {
|
||||
font-family: "Terminal";
|
||||
font-weight: bold;
|
||||
src: local("terminal-grotesque"),
|
||||
url("/assets/fonts/terminal-grotesque.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Danzza";
|
||||
src: local("Danzza Regular"),
|
||||
url("/assets/fonts/Danzza-Regular.woff") format("woff"),
|
||||
url("/assets/fonts/Danzza-Regular.otf") format("opentype");
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Danzza Light";
|
||||
src: local("Danzza Light"),
|
||||
url("/assets/fonts/Danzza-Light.woff") format("woff"),
|
||||
url("/assets/fonts/Danzza-Light.otf") format("opentype");
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Danzza Medium";
|
||||
src: local("Danzza Medium"),
|
||||
url("/assets/fonts/Danzza-Medium.woff") format("woff"),
|
||||
url("/assets/fonts/Danzza-Medium.otf") format("opentype");
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Danzza Bold";
|
||||
src: local("Danzza Bold"),
|
||||
url("/assets/fonts/Danzza-Bold.woff") format("woff"),
|
||||
url("/assets/fonts/Danzza-Bold.otf") format("opentype");
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* Font utility classes */
|
||||
.font-face-terminal {
|
||||
font-family: "Terminal";
|
||||
}
|
||||
|
||||
.font-face-danzza {
|
||||
font-family: "Danzza";
|
||||
}
|
||||
|
||||
.font-face-danzza-light {
|
||||
font-family: "Danzza Light";
|
||||
}
|
||||
|
||||
.font-face-danzza-medium {
|
||||
font-family: "Danzza Medium";
|
||||
}
|
||||
|
||||
.font-face-danzza-bold {
|
||||
font-family: "Danzza Bold";
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
/* Main styles entry point */
|
||||
@import './variables.css';
|
||||
@import './reset.css';
|
||||
@import './fonts.css';
|
||||
@import './layout.css';
|
||||
@import './buttons.css';
|
||||
@import './cursor.css';
|
||||
@import './utils.css';
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/* Golden Grid */
|
||||
.golden-grid {
|
||||
height: 100% !important;
|
||||
min-height: 100% !important;
|
||||
display: grid !important;
|
||||
position: relative;
|
||||
grid-template-rows: 1fr 1fr 2fr 4fr 2.66fr 5.33fr 5.33fr 4.33fr 2.83fr 3.5fr 3.5fr 2.83fr 4.33fr 5.33fr 5.33fr 2.66fr 4fr 2fr 1fr 1fr;
|
||||
grid-template-columns: 1fr 1fr 2fr 4fr 2.66fr 5.33fr 5.33fr 4.33fr 2.83fr 3.5fr 3.5fr 2.83fr 4.33fr 5.33fr 5.33fr 2.66fr 4fr 2fr 1fr 1fr;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.slide {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
/* Vertical Lines */
|
||||
.vertical-line {
|
||||
z-index: 1;
|
||||
border-left: 0.1px solid rgba(238, 238, 238, 0.2);
|
||||
height: 150%;
|
||||
}
|
||||
|
||||
.vertical-line-start {
|
||||
z-index: 1;
|
||||
border-left: 0.1px solid rgba(238, 238, 238, 0.2);
|
||||
grid-area: 1/6 / span 20 / span 1;
|
||||
height: 150%;
|
||||
}
|
||||
|
||||
.vertical-line-center {
|
||||
z-index: 1;
|
||||
border-left: 0.1px solid rgba(238, 238, 238, 0.2);
|
||||
grid-area: 1/11 / span 20 / span 1;
|
||||
height: 150%;
|
||||
}
|
||||
|
||||
.vertical-line-end {
|
||||
z-index: 1;
|
||||
border-left: 0.1px solid rgba(238, 238, 238, 0.2);
|
||||
grid-area: 1/16 / span 20 / span 1;
|
||||
height: 150%;
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
/* CSS Reset */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: none;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
min-height: 100vh;
|
||||
min-height: -webkit-fill-available;
|
||||
min-height: calc(var(--vh, 1vh) * 100);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Danzza Regular", "Danzza", -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
|
||||
"Droid Sans", "Helvetica Neue", sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background: var(--color-background);
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
@media (pointer: coarse) {
|
||||
body,
|
||||
* {
|
||||
cursor: auto;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
/* Selection */
|
||||
::selection {
|
||||
background: var(--color-primary);
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/* Scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--color-primary);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--color-primary-hover);
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/* CSS Variables */
|
||||
:root {
|
||||
/* Base font sizes for desktop */
|
||||
--font-size-paragraph: 18px;
|
||||
--font-size-paragraph-small: 16px;
|
||||
--font-size-subtitle: 20px;
|
||||
--font-size-title-section: 32px;
|
||||
--font-size-title-main: 48px;
|
||||
--font-size-title-hero: 96px;
|
||||
--font-size-button: 13px;
|
||||
--font-size-caption: 12px;
|
||||
|
||||
/* Mobile font sizes */
|
||||
--font-size-paragraph-mobile: 16px;
|
||||
--font-size-paragraph-small-mobile: 12px;
|
||||
--font-size-subtitle-mobile: 16px;
|
||||
--font-size-title-section-mobile: 24px;
|
||||
--font-size-title-main-mobile: 32px;
|
||||
--font-size-title-hero-mobile: 48px;
|
||||
--font-size-button-mobile: 11px;
|
||||
--font-size-caption-mobile: 10px;
|
||||
|
||||
/* Tablet font sizes */
|
||||
--font-size-paragraph-tablet: 16px;
|
||||
--font-size-paragraph-small-tablet: 14px;
|
||||
--font-size-subtitle-tablet: 18px;
|
||||
--font-size-title-section-tablet: 28px;
|
||||
--font-size-title-main-tablet: 40px;
|
||||
--font-size-title-hero-tablet: 64px;
|
||||
--font-size-button-tablet: 12px;
|
||||
--font-size-caption-tablet: 11px;
|
||||
|
||||
/* Colors */
|
||||
--color-primary: #04fea0;
|
||||
--color-primary-hover: #03d98c;
|
||||
--color-background: #000;
|
||||
--color-text: #fff;
|
||||
}
|
||||
|
|
@ -1,177 +0,0 @@
|
|||
<script>
|
||||
import { fade } from 'svelte/transition'
|
||||
|
||||
let { data } = $props()
|
||||
|
||||
const intro = $derived(data?.intro || {})
|
||||
const mission = $derived(data?.mission || {})
|
||||
const manifesto = $derived(data?.manifesto || {})
|
||||
const team = $derived(data?.team || {})
|
||||
</script>
|
||||
|
||||
<div class="about" transition:fade>
|
||||
<section class="about__intro">
|
||||
<h1>{intro.title || data?.title}</h1>
|
||||
{#if intro.text}
|
||||
<p class="about__intro-text">{@html intro.text}</p>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
{#if mission.text}
|
||||
<section class="about__section">
|
||||
<h2>{mission.title}</h2>
|
||||
<div class="about__section-content">
|
||||
{@html mission.text}
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
{#if manifesto.text}
|
||||
<section class="about__section">
|
||||
<h2>{manifesto.title}</h2>
|
||||
<div class="about__section-content">
|
||||
{@html manifesto.text}
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
{#if team.members && team.members.length > 0}
|
||||
<section class="about__team">
|
||||
<h2>{team.title}</h2>
|
||||
|
||||
<div class="about__team-grid">
|
||||
{#each team.members as member}
|
||||
<article class="team-card">
|
||||
{#if member.photo}
|
||||
<div class="team-card__photo">
|
||||
<img src={member.photo} alt={member.name} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="team-card__info">
|
||||
<h3>{member.name}</h3>
|
||||
<p class="team-card__role">{member.role}</p>
|
||||
|
||||
{#if member.bio}
|
||||
<p class="team-card__bio">{member.bio}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</article>
|
||||
{/each}
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.about {
|
||||
min-height: 100vh;
|
||||
padding: 8rem 2rem 4rem;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.about__intro {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto 6rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.about__intro h1 {
|
||||
font-size: clamp(2.5rem, 6vw, 5rem);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.about__intro-text {
|
||||
font-size: clamp(1.1rem, 2vw, 1.5rem);
|
||||
opacity: 0.9;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.about__section {
|
||||
max-width: 1200px;
|
||||
margin: 4rem auto;
|
||||
}
|
||||
|
||||
.about__section h2 {
|
||||
font-size: clamp(2rem, 4vw, 3rem);
|
||||
margin-bottom: 2rem;
|
||||
color: #04fea0;
|
||||
}
|
||||
|
||||
.about__section-content {
|
||||
line-height: 1.8;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.about__team {
|
||||
max-width: 1400px;
|
||||
margin: 6rem auto 0;
|
||||
}
|
||||
|
||||
.about__team h2 {
|
||||
font-size: clamp(2rem, 4vw, 3rem);
|
||||
margin-bottom: 3rem;
|
||||
text-align: center;
|
||||
color: #04fea0;
|
||||
}
|
||||
|
||||
.about__team-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.team-card {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
transition: transform 0.3s, border-color 0.3s;
|
||||
}
|
||||
|
||||
.team-card:hover {
|
||||
transform: translateY(-5px);
|
||||
border-color: #04fea0;
|
||||
}
|
||||
|
||||
.team-card__photo {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.team-card__photo img {
|
||||
width: 100%;
|
||||
height: 250px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.team-card h3 {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.team-card__role {
|
||||
color: #04fea0;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 1rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.team-card__bio {
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.6;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.about {
|
||||
padding: 6rem 1rem 3rem;
|
||||
}
|
||||
|
||||
.about__team-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<script>
|
||||
import { fade } from 'svelte/transition'
|
||||
let { data } = $props()
|
||||
</script>
|
||||
|
||||
<div class="article" transition:fade>
|
||||
<div class="article__container">
|
||||
<h1>{data?.title || 'Article'}</h1>
|
||||
<p>Article view - To be implemented</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.article {
|
||||
min-height: 100vh;
|
||||
padding: 8rem 2rem 4rem;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.article__container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<script>
|
||||
import { fade } from 'svelte/transition'
|
||||
let { data } = $props()
|
||||
</script>
|
||||
|
||||
<div class="blog" transition:fade>
|
||||
<div class="blog__container">
|
||||
<h1>{data?.title || 'Blog'}</h1>
|
||||
<p>Blog view - To be implemented</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.blog {
|
||||
min-height: 100vh;
|
||||
padding: 8rem 2rem 4rem;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.blog__container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
<script>
|
||||
import { fade } from 'svelte/transition'
|
||||
|
||||
let { data } = $props()
|
||||
</script>
|
||||
|
||||
<div class="default" transition:fade>
|
||||
<div class="default__container">
|
||||
<h1>{data?.title || 'Page'}</h1>
|
||||
{#if data?.body}
|
||||
<div class="default__content">
|
||||
{@html data.body}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.default {
|
||||
min-height: 100vh;
|
||||
padding: 8rem 2rem 4rem;
|
||||
}
|
||||
|
||||
.default__container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(2rem, 5vw, 4rem);
|
||||
margin-bottom: 2rem;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.default__content {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.default {
|
||||
padding: 6rem 1rem 3rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<script>
|
||||
import { fade } from 'svelte/transition'
|
||||
let { data } = $props()
|
||||
</script>
|
||||
|
||||
<div class="expertise" transition:fade>
|
||||
<div class="expertise__container">
|
||||
<h1>{data?.title || 'Expertise'}</h1>
|
||||
<p>Expertise view - To be implemented</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.expertise {
|
||||
min-height: 100vh;
|
||||
padding: 8rem 2rem 4rem;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.expertise__container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<script>
|
||||
import { fade } from 'svelte/transition'
|
||||
let { data } = $props()
|
||||
</script>
|
||||
|
||||
<div class="game" transition:fade>
|
||||
<div class="game__container">
|
||||
<h1>{data?.title || 'Game'}</h1>
|
||||
<p>Game view - To be implemented</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.game {
|
||||
min-height: 100vh;
|
||||
padding: 8rem 2rem 4rem;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.game__container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,218 +0,0 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte'
|
||||
import { locale } from '@state/locale.svelte'
|
||||
import { navigateTo } from '@state/router'
|
||||
|
||||
let { data } = $props()
|
||||
|
||||
const currentLang = $derived(locale.current)
|
||||
|
||||
const translations = {
|
||||
homeText: {
|
||||
fr: "World Game crée des expériences gamifiées qui transforment l'engagement en résultats mesurables",
|
||||
en: "World Game creates gamified experiences that transform engagement into measurable results"
|
||||
},
|
||||
explore: {
|
||||
fr: "EXPLORER",
|
||||
en: "EXPLORE"
|
||||
}
|
||||
}
|
||||
|
||||
function t(key) {
|
||||
return translations[key]?.[currentLang] || translations[key]?.fr || ''
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const playVideo = async (videoId) => {
|
||||
const video = document.getElementById(videoId)
|
||||
if (video) {
|
||||
try {
|
||||
video.muted = true
|
||||
video.playsInline = true
|
||||
const playPromise = video.play()
|
||||
if (playPromise !== undefined) {
|
||||
await playPromise
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`Autoplay failed for ${videoId}:`, error)
|
||||
const playOnInteraction = () => {
|
||||
video.play().catch(e => console.log('Fallback play failed:', e))
|
||||
document.removeEventListener('click', playOnInteraction)
|
||||
document.removeEventListener('touchstart', playOnInteraction)
|
||||
}
|
||||
document.addEventListener('click', playOnInteraction)
|
||||
document.addEventListener('touchstart', playOnInteraction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
playVideo('home-video')
|
||||
playVideo('home-video-mobile')
|
||||
}, 100)
|
||||
|
||||
return () => clearTimeout(timer)
|
||||
})
|
||||
|
||||
function handleExplore() {
|
||||
navigateTo('/portfolio')
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="home golden-grid slide" data-anchor="HOME">
|
||||
<div style="grid-area: 1/1/span 20/span 20; filter: saturate(140%);">
|
||||
<div class="olly">
|
||||
<figure
|
||||
style="
|
||||
height: -webkit-fill-available;
|
||||
width: -webkit-fill-available;
|
||||
"
|
||||
>
|
||||
<video
|
||||
muted
|
||||
autoplay
|
||||
playsinline
|
||||
loop
|
||||
controls={false}
|
||||
preload="metadata"
|
||||
id="home-video"
|
||||
class="home-video home-video-desktop"
|
||||
style="
|
||||
object-fit: cover;
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
height: -webkit-fill-available;
|
||||
width: -webkit-fill-available;
|
||||
"
|
||||
>
|
||||
<source
|
||||
src="/assets/video/Website_version.mp4"
|
||||
type="video/mp4"
|
||||
/>
|
||||
</video>
|
||||
<video
|
||||
muted
|
||||
autoplay
|
||||
playsinline
|
||||
loop
|
||||
controls={false}
|
||||
preload="metadata"
|
||||
id="home-video-mobile"
|
||||
class="home-video-mobile"
|
||||
style="
|
||||
object-fit: cover;
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
height: -webkit-fill-available;
|
||||
width: -webkit-fill-available;
|
||||
"
|
||||
>
|
||||
<source
|
||||
src="/assets/video/mobile_version_texte_fixe.mp4"
|
||||
type="video/mp4"
|
||||
/>
|
||||
</video>
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="vertical-line-start"></div>
|
||||
<div class="vertical-line-center"></div>
|
||||
<div class="vertical-line-end"></div>
|
||||
|
||||
<div
|
||||
class="home-text"
|
||||
style="z-index: 5; justify-self: center; margin-top: 6vmax;"
|
||||
>
|
||||
<h2 class="font-face-danzza-light home-subtitle">
|
||||
{t('homeText')}
|
||||
</h2>
|
||||
<div
|
||||
class="clickable button"
|
||||
style="margin: auto; margin-top: 40px;"
|
||||
onclick={handleExplore}
|
||||
onkeypress={(e) => e.key === 'Enter' && handleExplore()}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="earth-icon clickable-filter-black"></div>
|
||||
<p class="clickable" style="font-family: Terminal; font-size: 1.2em;">
|
||||
{t('explore')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.home {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.home-text {
|
||||
z-index: 9;
|
||||
grid-area: 9/1 / span 6 / span 20;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.home-subtitle {
|
||||
font-size: var(--font-size-subtitle);
|
||||
color: white;
|
||||
width: 30%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.olly {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.olly figure {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.home-video {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.home-video-desktop {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.home-video-mobile {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1000px) {
|
||||
.home-video-desktop {
|
||||
display: none !important;
|
||||
}
|
||||
.home-video-mobile {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.home-subtitle {
|
||||
font-size: var(--font-size-subtitle-mobile);
|
||||
width: 80%;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 701px) and (max-width: 912px) {
|
||||
.home-subtitle {
|
||||
font-size: var(--font-size-subtitle-tablet);
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<script>
|
||||
import { fade } from 'svelte/transition'
|
||||
let { data } = $props()
|
||||
</script>
|
||||
|
||||
<div class="jouer" transition:fade>
|
||||
<div class="jouer__container">
|
||||
<h1>{data?.title || 'Jouer'}</h1>
|
||||
<p>Jouer view - To be implemented</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.jouer {
|
||||
min-height: 100vh;
|
||||
padding: 8rem 2rem 4rem;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.jouer__container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<script>
|
||||
import { fade } from 'svelte/transition'
|
||||
let { data } = $props()
|
||||
</script>
|
||||
|
||||
<div class="portfolio" transition:fade>
|
||||
<div class="portfolio__container">
|
||||
<h1>{data?.title || 'Portfolio'}</h1>
|
||||
<p>Portfolio view - To be implemented</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.portfolio {
|
||||
min-height: 100vh;
|
||||
padding: 8rem 2rem 4rem;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.portfolio__container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<script>
|
||||
import { fade } from 'svelte/transition'
|
||||
let { data } = $props()
|
||||
</script>
|
||||
|
||||
<div class="project" transition:fade>
|
||||
<div class="project__container">
|
||||
<h1>{data?.title || 'Project'}</h1>
|
||||
<p>Project view - To be implemented</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.project {
|
||||
min-height: 100vh;
|
||||
padding: 8rem 2rem 4rem;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.project__container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
|
||||
|
||||
export default {
|
||||
preprocess: vitePreprocess()
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
||||
import path from 'path'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
svelte({
|
||||
configFile: './svelte.config.js'
|
||||
})
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@components': path.resolve(__dirname, 'src/components'),
|
||||
'@views': path.resolve(__dirname, 'src/views'),
|
||||
'@state': path.resolve(__dirname, 'src/state')
|
||||
}
|
||||
},
|
||||
server: {
|
||||
port: 5173,
|
||||
proxy: {
|
||||
'^(?!/@vite|/@fs|/node_modules|/src).*': {
|
||||
target: 'http://localhost:8000',
|
||||
changeOrigin: true
|
||||
}
|
||||
}
|
||||
},
|
||||
build: {
|
||||
outDir: 'assets/dist',
|
||||
emptyOutDir: true,
|
||||
manifest: false,
|
||||
rollupOptions: {
|
||||
input: 'src/main.js',
|
||||
output: {
|
||||
entryFileNames: 'index.js',
|
||||
chunkFileNames: '[name].js',
|
||||
assetFileNames: '[name].[ext]'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue