Transferred and translated the frontend code from L10 to L12
@ -51,6 +51,12 @@ class HandleInertiaRequests extends Middleware
|
|||||||
'location' => $request->url(),
|
'location' => $request->url(),
|
||||||
],
|
],
|
||||||
'sidebarOpen' => ! $request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true',
|
'sidebarOpen' => ! $request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true',
|
||||||
|
'flash' => [
|
||||||
|
'message' => fn () => $request->session()->get('message'),
|
||||||
|
'success' => fn () => $request->session()->get('success'),
|
||||||
|
'warning' => fn () => $request->session()->get('warning'),
|
||||||
|
'error' => fn () => $request->session()->get('error'),
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
package-lock.json
generated
@ -6,7 +6,7 @@
|
|||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@inertiajs/vue3": "^2.0.0",
|
"@inertiajs/vue3": "^2.0.0",
|
||||||
"@tailwindcss/vite": "^4.1.1",
|
"@tailwindcss/vite": "^4.1.5",
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
"@vueuse/core": "^12.8.2",
|
"@vueuse/core": "^12.8.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
@ -19,7 +19,7 @@
|
|||||||
"marked": "^9.1.6",
|
"marked": "^9.1.6",
|
||||||
"reka-ui": "^2.2.0",
|
"reka-ui": "^2.2.0",
|
||||||
"tailwind-merge": "^3.2.0",
|
"tailwind-merge": "^3.2.0",
|
||||||
"tailwindcss": "^4.1.1",
|
"tailwindcss": "^4.1.5",
|
||||||
"tw-animate-css": "^1.2.5",
|
"tw-animate-css": "^1.2.5",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"uuidv4": "^6.2.13",
|
"uuidv4": "^6.2.13",
|
||||||
|
26
package.json
@ -16,37 +16,37 @@
|
|||||||
"eslint": "^9.17.0",
|
"eslint": "^9.17.0",
|
||||||
"eslint-config-prettier": "^10.0.1",
|
"eslint-config-prettier": "^10.0.1",
|
||||||
"eslint-plugin-vue": "^9.32.0",
|
"eslint-plugin-vue": "^9.32.0",
|
||||||
|
"flowbite": "^1.8.1",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"prettier-plugin-organize-imports": "^4.1.0",
|
"prettier-plugin-organize-imports": "^4.1.0",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||||
"typescript-eslint": "^8.23.0",
|
"typescript-eslint": "^8.23.0",
|
||||||
"vue-tsc": "^2.2.4",
|
"vue-tsc": "^2.2.4"
|
||||||
"flowbite": "^1.8.1"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@inertiajs/vue3": "^2.0.0",
|
"@inertiajs/vue3": "^2.0.0",
|
||||||
"@tailwindcss/vite": "^4.1.1",
|
"@tailwindcss/vite": "^4.1.5",
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
"@vueuse/core": "^12.8.2",
|
"@vueuse/core": "^12.8.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"concurrently": "^9.0.1",
|
"concurrently": "^9.0.1",
|
||||||
|
"gsap": "^3.12.2",
|
||||||
"laravel-vite-plugin": "^1.0",
|
"laravel-vite-plugin": "^1.0",
|
||||||
"lucide-vue-next": "^0.468.0",
|
"lucide-vue-next": "^0.468.0",
|
||||||
"reka-ui": "^2.2.0",
|
|
||||||
"tailwind-merge": "^3.2.0",
|
|
||||||
"tailwindcss": "^4.1.1",
|
|
||||||
"tw-animate-css": "^1.2.5",
|
|
||||||
"typescript": "^5.2.2",
|
|
||||||
"vite": "^6.2.0",
|
|
||||||
"vue": "^3.5.13",
|
|
||||||
"gsap": "^3.12.2",
|
|
||||||
"markdown-it": "^13.0.1",
|
"markdown-it": "^13.0.1",
|
||||||
"marked": "^9.1.6",
|
"marked": "^9.1.6",
|
||||||
|
"reka-ui": "^2.2.0",
|
||||||
|
"tailwind-merge": "^3.2.0",
|
||||||
|
"tailwindcss": "^4.1.5",
|
||||||
|
"tw-animate-css": "^1.2.5",
|
||||||
|
"typescript": "^5.2.2",
|
||||||
"uuidv4": "^6.2.13",
|
"uuidv4": "^6.2.13",
|
||||||
"ziggy-js": "^2.4.2",
|
"vite": "^6.2.0",
|
||||||
|
"vue": "^3.5.13",
|
||||||
"vue3-tree": "^0.11.5",
|
"vue3-tree": "^0.11.5",
|
||||||
"vue3-treeview": "^0.4.2"
|
"vue3-treeview": "^0.4.2",
|
||||||
|
"ziggy-js": "^2.4.2"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
"@rollup/rollup-linux-x64-gnu": "4.9.5",
|
||||||
|
BIN
public/img/appstore.jpg
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
public/img/bakgrunn.png
Normal file
After Width: | Height: | Size: 1.4 MiB |
BIN
public/img/forgrunn-r.png
Normal file
After Width: | Height: | Size: 322 KiB |
BIN
public/img/forgrunn.png
Normal file
After Width: | Height: | Size: 604 KiB |
BIN
public/img/maillogo.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
public/img/medlemmer-bg.jpg
Normal file
After Width: | Height: | Size: 534 KiB |
BIN
public/img/medlemmer.jpg
Normal file
After Width: | Height: | Size: 1.4 MiB |
BIN
public/img/meny-bak-1.jpg
Normal file
After Width: | Height: | Size: 175 KiB |
BIN
public/img/meny-bak-2.jpg
Normal file
After Width: | Height: | Size: 695 KiB |
BIN
public/img/oms-glow.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
public/img/oms.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
public/img/pexels-andrew-neel-2859169.jpg
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
public/img/pexels-flenn-may-802505.jpg
Normal file
After Width: | Height: | Size: 3.5 MiB |
BIN
public/img/pexels-ketut-subiyanto-4963437.jpg
Normal file
After Width: | Height: | Size: 3.1 MiB |
BIN
public/img/pexels-rodrigo-santos-3888151.jpg
Normal file
After Width: | Height: | Size: 2.1 MiB |
BIN
public/img/pexels-sebastian-ervi-1763075.jpg
Normal file
After Width: | Height: | Size: 1.3 MiB |
BIN
public/img/playstore.jpg
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
public/img/sol-center.png
Normal file
After Width: | Height: | Size: 150 KiB |
BIN
public/img/sol-left.png
Normal file
After Width: | Height: | Size: 221 KiB |
BIN
public/img/sol-right.png
Normal file
After Width: | Height: | Size: 280 KiB |
BIN
public/img/splash.jpg
Normal file
After Width: | Height: | Size: 213 KiB |
@ -7,11 +7,95 @@
|
|||||||
|
|
||||||
@custom-variant dark (&:is(.dark *));
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'TopSecret';
|
||||||
|
src: url('/fonts/topsecret.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('/fonts/roboto-standard.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('/fonts/roboto-medium.ttf') format('truetype');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('/fonts/roboto-bold.ttf') format('truetype');
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('/fonts/roboto-black.ttf') format('truetype');
|
||||||
|
font-weight: 900;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('/fonts/roboto-italic.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'CallOfDuty';
|
||||||
|
src: url('/fonts/callofduty.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "MicrogrammaD";
|
||||||
|
src: url("/fonts/MicroD.otf") format("opentype");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "MontserratBold";
|
||||||
|
src: url("/fonts/MontBold.ttf") format("truetype");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
--font-sans:
|
--font-sans: Instrument Sans, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji',
|
||||||
Instrument Sans, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji',
|
|
||||||
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||||
|
|
||||||
|
--font-arctic: MicrogrammaD, "sans-serif";
|
||||||
|
--font-software: MontserratBold, "ui-sans-serif";
|
||||||
|
--font-topsecret: TopSecret, "system-ui";
|
||||||
|
--font-callofduty: CallOfDuty, MicrogrammaD, "ui-sans-serif";
|
||||||
|
|
||||||
|
--background-image-logoBg: url('/img/oms.png');
|
||||||
|
--background-image-heroBgBackup: url('/img/illustration-full.png');
|
||||||
|
--background-image-heroBg: url('/img/bakgrunn.png');
|
||||||
|
--background-image-heroFg: url('/img/forgrunn.png');
|
||||||
|
--background-image-heroFgR: url('/img/forgrunn-r.png');
|
||||||
|
--background-image-heroSoldiers: url('/img/sol-center.png');
|
||||||
|
--background-image-splashBg: url('/img/splash.jpg');
|
||||||
|
--background-image-sightBg: url('/img/sight.png');
|
||||||
|
--background-image-maps: url('/img/pexels-andrew-neel-2859169.jpg');
|
||||||
|
--background-image-camuflage-lgreen: url('/img/6-green-camouflage-texture-tile-1.png');
|
||||||
|
--background-image-camuflage-dgreen: url('/img/6-green-camouflage-texture-tile-6.png');
|
||||||
|
--background-image-garden-party: url('/img/pexels-flenn-may-802505.jpg');
|
||||||
|
--background-image-event: url('/img/pexels-sebastian-ervi-1763075.jpg');
|
||||||
|
--background-image-night: url('/img/meny-bak-2.jpg');
|
||||||
|
--background-image-medlemmer: url('/img/medlemmer-bg.jpg');
|
||||||
|
|
||||||
|
|
||||||
--radius-lg: var(--radius);
|
--radius-lg: var(--radius);
|
||||||
--radius-md: calc(var(--radius) - 2px);
|
--radius-md: calc(var(--radius) - 2px);
|
||||||
--radius-sm: calc(var(--radius) - 4px);
|
--radius-sm: calc(var(--radius) - 4px);
|
||||||
|
340
resources/js/Utils/blocks.js
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
// @/Utils/blocks.js
|
||||||
|
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
const blocks = {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
uuid: 'group-heroes',
|
||||||
|
title: 'Hero-seksjoner',
|
||||||
|
blocks: [
|
||||||
|
{
|
||||||
|
uuid: uuidv4(),
|
||||||
|
componentName: 'HeroLogoText',
|
||||||
|
optionsComponentName: 'HeroLogoTextOptions',
|
||||||
|
renderComponentName: 'HeroLogoTextRendered',
|
||||||
|
description: 'Hero tekst, logo og lenke',
|
||||||
|
thumbUrl: '/img/blocks/hero_logo_text_preview.jpg',
|
||||||
|
static: false,
|
||||||
|
title: 'Bygg en fantastisk hjemmeside for deg og dine brukere med',
|
||||||
|
titlecursive: 'PolarPress web applikasjon',
|
||||||
|
showtitle: true,
|
||||||
|
texts: [
|
||||||
|
{
|
||||||
|
paragraph: 'Trenger du et enkelt og fleksibelt system for å organisere din klubb og klubbaktiviteter, uten å knekke lommeboka? Ønsker du et partnerskap med en utvikler med tilhold i Norge og som er lett tilgjengelig dersom du har behov for oppfølging? Kontakt oss for mer informasjon om hvordan vi kan hjelpe deg og din klubb'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
buttontext: 'Kontakt oss',
|
||||||
|
buttonaction: 'none',
|
||||||
|
buttonlink: '',
|
||||||
|
showbutton: true,
|
||||||
|
showlogo: true,
|
||||||
|
anchorName: 'frontPageArcticSoftware',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: 'group-faqs',
|
||||||
|
title: 'Spørsmål og svar',
|
||||||
|
blocks: [
|
||||||
|
{
|
||||||
|
uuid: uuidv4(),
|
||||||
|
componentName: 'FAQList',
|
||||||
|
optionsComponentName: 'FAQListOptions',
|
||||||
|
renderComponentName: 'FAQListRendered',
|
||||||
|
description: 'En enkel liste med spørsmål og svar',
|
||||||
|
thumbUrl: '/img/blocks/list.jpg',
|
||||||
|
title: 'Ofte stilte spørsmål',
|
||||||
|
static: false,
|
||||||
|
faqs: [
|
||||||
|
{ question: 'Hva er dette?', answer: 'Dette er en FAQ blokk.' },
|
||||||
|
{ question: 'Hvordan bruker jeg det?', answer: 'Legg inn spørsmål og svar her.' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: uuidv4(),
|
||||||
|
componentName: 'FAQCollapse',
|
||||||
|
optionsComponentName: 'FAQCollapseOptions',
|
||||||
|
renderComponentName: 'FAQCollapseRendered',
|
||||||
|
description: 'Kollapsbare spørsmål og svar',
|
||||||
|
thumbUrl: '/img/blocks/collapse.jpg',
|
||||||
|
title: 'FAQ Seksjon',
|
||||||
|
static: false,
|
||||||
|
faqs: [
|
||||||
|
{ question: 'Hva er dette?', answer: 'Dette er et eksempel på et spørsmål og svar.' },
|
||||||
|
{ question: 'Hvordan fungerer det?', answer: 'Du legger til innhold og publiserer siden.' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: uuidv4(),
|
||||||
|
componentName: 'FAQCondensed',
|
||||||
|
optionsComponentName: 'FAQCondensedOptions',
|
||||||
|
renderComponentName: 'FAQCondensedRendered',
|
||||||
|
description: 'Kondensert og animert spørsmål og svar',
|
||||||
|
thumbUrl: '/img/blocks/faq_condensed_preview.jpg',
|
||||||
|
static: false,
|
||||||
|
title: 'Spørsmål angående denne siden?',
|
||||||
|
titlecursive: 'Her er noen svar',
|
||||||
|
showtitle: true,
|
||||||
|
label: 'OM DEMOSIDEN',
|
||||||
|
showlabel: true,
|
||||||
|
anchorName: 'frontPageFAQ',
|
||||||
|
faqs: [
|
||||||
|
{
|
||||||
|
categoryName: 'Kategori 1',
|
||||||
|
categoryContent: [
|
||||||
|
{ question: 'Spørsmål 1', answer: 'Dette er svar på spørsmål 1', state: false },
|
||||||
|
{ question: 'Spørsmål 2', answer: 'Dette er svar på spørsmål 2', state: false },
|
||||||
|
{ question: 'Spørsmål 3', answer: 'Dette er svar på spørsmål 3', state: false }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
categoryName: 'Kategori 2',
|
||||||
|
categoryContent: [
|
||||||
|
{ question: 'Spørsmål 4', answer: 'Dette er svar på spørsmål 4', state: false },
|
||||||
|
{ question: 'Spørsmål 5', answer: 'Dette er svar på spørsmål 5', state: false },
|
||||||
|
{ question: 'Spørsmål 6', answer: 'Dette er svar på spørsmål 6', state: false }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: 'text-content',
|
||||||
|
title: 'Blokker ment for lengre tekstinnlegg',
|
||||||
|
blocks: [
|
||||||
|
{
|
||||||
|
uuid: uuidv4(),
|
||||||
|
componentName: 'TwoColumnText',
|
||||||
|
optionsComponentName: 'TwoColumnTextOptions',
|
||||||
|
renderComponentName: 'TwoColumnTextRendered',
|
||||||
|
description: 'Tekstblokk med to kolonner (en på små skjermer)',
|
||||||
|
thumbUrl: '/img/blocks/twocolumntext_oms_preview.jpg',
|
||||||
|
static: false,
|
||||||
|
anchorName: 'content',
|
||||||
|
|
||||||
|
firstcolumn: [
|
||||||
|
{
|
||||||
|
text: 'Litt om vår klubb',
|
||||||
|
style: 'headinglarge'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'To tiår med fellesskap og lidenskap for airsoft',
|
||||||
|
style: 'heading'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Østfold Milsim er en airsoftklubb som ble stiftet i 2003. Klubben startet opp med et fokus på Milsim, men har i dag en mer variert spillestil. Milsim etterstreber å være mest "korrekt" ut fra hvilket utstyr og uniform man bruker, mens klubben i dag har en stor variasjon av spillere. Her er man velkommen uansett om man spiller i hettegenser eller fullt airsoft kit. Vi tilhører Hyperion, Norsk Forbund for Fantastiske Fritidsinteresser (n4f.no)',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Vår hobby er airsoft (softguns). Vi arrangerer egne spill og deltar på andre klubbers spill. På større spill eller samlinger overnattes det ute i skogen der arrangementet foregår. Klubbens symbol er en gaupepote, det største fastboende rovdyret i Østfold.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Arrangementer',
|
||||||
|
style: 'headingbold'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Vi arrangerer egne spill og deltar på andre klubbers spill. Det spilles på lørdag eller søndag, som oftest med matpause og sosialisering midt i spilltiden. Det kan være alt fra 15 til 100 deltakere på lokale spill.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'På storspill (samlinger) spilles det over flere dager med overnatting i telt. På utenlandske spill kan det være opp mot 2000 spillere. Storspill i Norge har fra 100 til 400 spillere. ØMS har en god del friluftsutstyr som medlemmer kan låne gratis ved deltakelse på slike samlinger.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Airsoft som aktivitet',
|
||||||
|
style: 'headingbold'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Airsoft er en sosial, inkluderende og spennende hobby. Her kan man velge om man ønsker å spille på lag eller for seg selv. Spillarrangøren avgjør spillets gang, men man er velkommen både alene og som en gjeng. Airsoft er en betegnelse på hvordan man rollespiller med softguns. Arrangementene følger forskjellige scenarioer og har ulike mål for hvert spill. Aktiviteten legger opp til mye samarbeid, kommunikasjon og problemløsning.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Selv om det i stor grad oppfordres til en del aktivitet, er airsoft en hobby som er lett å tilpasse sitt eget aktivitetsnivå. Det er ganske unikt som en aktiv hobby i sin mulighet til å variere og tilpasse ut fra dagsformen. Her trenger du ikke være best, her kan du bare være deg selv. Airsoftere er både unge og eldre, i alle forskjellige yrker, kvinner og menn. Dette er med andre ord en hobby for absolutt alle som ønsker å være aktive og treffe andre.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Utstyr',
|
||||||
|
style: 'headingbold'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Det er ikke noe krav til utstyr utover briller og en softgun. Du kan leie utstyr billig av ØMS hvis du/dere vil prøve å spille. Vi selger også kuler, ta kontakt med oss på Facebook for dette.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Ønsker du å bli en mer aktiv spiller, vil du sannsynligvis se fordelene med en uniform i form av kamuflasje. Gode støvler for å hindre overtråkk og å holde føttene tørre. Noe å ha magasiner i (vest/chestrig). Det finnes egne salgskanaler for brukt airsoftutstyr, samt sider som finn.no.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Som medlem av ØMS får du "no bullshit" råd om utstyr som passer deg og din økonomi, samt hjelp til å finne seriøse og gode aktører på airsoft markedet.',
|
||||||
|
style: 'regular'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
secondcolumn: [
|
||||||
|
{
|
||||||
|
text: 'Litt om airsoft',
|
||||||
|
style: 'headinglarge'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Trygge spill, uforglemmelige øyeblikk. Lær mer om airsoft og hvor man skal begynne.',
|
||||||
|
style: 'heading'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'https://www.youtube.com/embed/ZJZyK88_3qE?si=VLjj2hJj0UNnWaG9',
|
||||||
|
style: 'video'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Softgun (våpnene vi bruker) har 18 års aldersgrense for å eie ifølge norsk våpenlov.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'På ØMS sine arrangementer kan du spille fra du er 14 år. Du får da en verge/trustee som klubben står for, og som vil følge deg i spill. Denne personen vil veilede og ta vare på deg som er 14-18 år under våre arrangementer.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Airsoft ble oppfunnet i Japan på 1980-tallet, og mange airsoftvåpen kopierer et originalt våpen. Softguns skyter 6 mm runde bionedbrytbare kuler med en utgangshastighet på 70-150 m/s. Disse veier 0,20-0,40 g og har derfor liten anslagsenergi.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Det er selvfølgelig krav om godkjente briller/maske under alle spill. Det er langt større sjanse for å vrikke ankelen under spill enn å bli skadet av et treff.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'I Norge har man klare regler på hvor hardt våpnene har lov til å skyte, og her følger vi Norsk Airsoft Forening sine regler med unntak av våres innendørs regler. Våpnene har en rekkevidde fra 50 m til 100 m.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Et airsoftvåpen er enten drevet av en fjær som må trekkes opp før hvert skudd, med gass, luft eller med elektrisk motor.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Airsoft er rollespill, ikke en form for "krigstrening". Det som skiller airsoft fra paintball er hovedsakelig at det er lagt vekt på realisme i våpen og utstyr, og at det ikke er maling i kulene.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "Airsoft kuler/BB's",
|
||||||
|
style: 'headingbold'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Kulene (BBs) har forskjellig vekt og er runde med en diameter på 6 mm. ØMS bruker biologiske kuler som brytes naturlig ned i naturen og er laget av materialer som ikke er giftige.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Kulene etterlater seg ingen farge i motsetning til paintball.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Hvordan begynne med Airsoft',
|
||||||
|
style: 'headingbold'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Du kan leie utstyr av oss for å prøve om airsoft er noe for deg før du går til innkjøp av eget utstyr. Har du allerede utstyr er det bare å melde seg på spill.',
|
||||||
|
style: 'regular'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Ta kontakt med oss og meld deg på spill så "treffes" vi!',
|
||||||
|
style: 'regular'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: 'static-content',
|
||||||
|
title: 'Statisk innhold',
|
||||||
|
blocks: [
|
||||||
|
{
|
||||||
|
uuid: uuidv4(),
|
||||||
|
componentName: 'FrontPageMenuHeader',
|
||||||
|
optionsComponentName: 'FrontPageMenuHeaderOptions',
|
||||||
|
renderComponentName: 'FrontPageMenuHeaderRendered',
|
||||||
|
description: 'Forside toppkomponent og header',
|
||||||
|
thumbUrl: '/img/blocks/frontpagemenuheader_oms_preview.jpg',
|
||||||
|
static: false,
|
||||||
|
title: 'Østfold Milsim',
|
||||||
|
anchorName: 'frontPageHeader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: uuidv4(),
|
||||||
|
componentName: 'FrontPageSponsors',
|
||||||
|
optionsComponentName: 'FrontPageSponsorsOptions',
|
||||||
|
renderComponentName: 'FrontPageSponsorsRendered',
|
||||||
|
description: 'Forside sponsorliste',
|
||||||
|
thumbUrl: '/img/blocks/frontpagesponsors_oms_preview.jpg',
|
||||||
|
static: false,
|
||||||
|
title: 'Våre sponsorer',
|
||||||
|
text: 'En stor takk til våre sponsorer som gjør det mulig for oss å drive klubben og holde arrangementer. Hvis du ønsker å bli en sponsor for klubben, ta kontakt med oss på sponsor alfakrøll ostfoldmilsim punktum no . Her kan du se en liste over våre sponsorer og sammarbeidspartnere. Klikk på en oppføring for å lese mer.',
|
||||||
|
partnertext: 'Hos våre sammarbeidspartnere får du rabatter på airsoftutstyr og andre varer. Klikk på en oppføring for å lese mer. Husk å logge deg inn hvis du er medlem for å se rabattkodene og annen nyttig informasjon sombare er tilgjengelig for våre medlemmer.',
|
||||||
|
showtext: true,
|
||||||
|
showpartnertext: true,
|
||||||
|
image: '/img/pexels-flenn-may-802505.jpg',
|
||||||
|
anchorName: 'sponsors-intro',
|
||||||
|
needs: ['sponsors', 'partners']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: uuidv4(),
|
||||||
|
componentName: 'FrontPageMembershipInfo',
|
||||||
|
optionsComponentName: 'FrontPageMembershipInfoOptions',
|
||||||
|
renderComponentName: 'FrontPageMembershipInfoRendered',
|
||||||
|
description: 'Medlemskapsinformasjon',
|
||||||
|
thumbUrl: '/img/blocks/frontpagemembers_oms_preview.jpg',
|
||||||
|
static: false,
|
||||||
|
showprices: true,
|
||||||
|
title: 'Medlemskap',
|
||||||
|
text: 'Som medlem får du tilgang til våre arrangementer, rabatter hos våre sponsorer, mulighet til å låne utstyr til en rimligere pris fra klubben og du får rimligere pris på våre spillavgifter. Du får også tilgang til nyttig informasjon, vår intergruppe på facebook og kan delta i diskusjoner via våre kommentarfelt.',
|
||||||
|
image: '/img/medlemmer-bg.jpg',
|
||||||
|
anchorName: 'membership',
|
||||||
|
needs: ['contingent']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: uuidv4(),
|
||||||
|
componentName: 'FrontPageNewsList',
|
||||||
|
optionsComponentName: 'FrontPageNewsListOptions',
|
||||||
|
renderComponentName: 'FrontPageNewsListRendered',
|
||||||
|
description: 'Nyhetsartikler',
|
||||||
|
thumbUrl: '/img/blocks/frontpagenews_oms_preview.jpg',
|
||||||
|
static: false,
|
||||||
|
title: 'Nyheter',
|
||||||
|
showtitle: true,
|
||||||
|
label: 'Hold deg oppdatert med hva som skjer i ØMS',
|
||||||
|
anchorName: 'intro',
|
||||||
|
showlabel: true,
|
||||||
|
image: '/img/pexels-andrew-neel-2859169.jpg',
|
||||||
|
buttontext: 'Vis flere nyheter',
|
||||||
|
needs: ['articles']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: uuidv4(),
|
||||||
|
componentName: 'FrontPageEventsList',
|
||||||
|
optionsComponentName: 'FrontPageEventsListOptions',
|
||||||
|
renderComponentName: 'FrontPageEventsListRendered',
|
||||||
|
description: 'Arrangementer',
|
||||||
|
thumbUrl: '/img/blocks/frontpageevents_oms_preview.jpg',
|
||||||
|
static: false,
|
||||||
|
title: 'Arrangementer',
|
||||||
|
showtitle: true,
|
||||||
|
label: 'Meld deg på og delta i fremtidige arrangementer',
|
||||||
|
showlabel: true,
|
||||||
|
secondarylabel: '(Registrerte og innloggede brukere/medlemmer vil ha tilgang til flere arrangementer)',
|
||||||
|
showsecondarylabel: true,
|
||||||
|
image: '/img/pexels-sebastian-ervi-1763075.jpg',
|
||||||
|
anchorName: 'events',
|
||||||
|
needs: ['events']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: uuidv4(),
|
||||||
|
componentName: 'PageFooter',
|
||||||
|
renderComponentName: 'PageFooterRendered',
|
||||||
|
description: 'Bunntekst/footer',
|
||||||
|
thumbUrl: '/img/blocks/footer_oms_preview.jpg',
|
||||||
|
static: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default blocks;
|
3
resources/js/components/ApplicationLogo.vue
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
<img src="/img/oms.png" class="w-12 h-12" alt="ØMS Logo">
|
||||||
|
</template>
|
17
resources/js/components/ArcticFooterLogo.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
<div class="w-24">
|
||||||
|
<img src="/img/as-logo-us.png" alt="Arctic Software PolarPress logo">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="ml-2">
|
||||||
|
<h2 class="text-2xl text-sky-400 font-arctic">Polar<span class="text-sky-700">Press</span></h2>
|
||||||
|
<h4 class="text-sm text-black dark:text-gray-300">Medlemsapplikasjon og publiseringssystem</h4>
|
||||||
|
<span class="text-xs text-right text-black dark:text-white">av <a target="_new" href="https://arcticsoftware.no" class="text-primary-800 underline font-semibold hover:text-primary-500 hover:no-underline hover:font-normal">Arctic Software AS</a></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
66
resources/js/components/Blocks/BlockGroup.vue
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<script setup>
|
||||||
|
import { defineProps, ref } from 'vue';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
title: String,
|
||||||
|
blocks: Array
|
||||||
|
});
|
||||||
|
|
||||||
|
const open = ref(false)
|
||||||
|
|
||||||
|
const clone = (block) => {
|
||||||
|
return {
|
||||||
|
...block,
|
||||||
|
uuid: uuidv4()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDragStart(event, block) {
|
||||||
|
event.dataTransfer.setData('application/json', JSON.stringify(block));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="accordion-blocks" data-accordion="collapse">
|
||||||
|
<div class="border border-gray-200 dark:border-gray-700 rounded-md">
|
||||||
|
<h2>
|
||||||
|
<button
|
||||||
|
@click="open = !open"
|
||||||
|
type="button"
|
||||||
|
class="flex items-center justify-between w-full px-4 py-2 font-medium text-left text-gray-800 dark:text-gray-200 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700"
|
||||||
|
>
|
||||||
|
{{ title }}
|
||||||
|
<svg
|
||||||
|
:class="{ 'rotate-180': open }"
|
||||||
|
class="w-4 h-4 transform transition-transform duration-300"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div v-show="open" class="px-4 pb-4 space-y-4 border-t border-gray-200 dark:border-gray-700">
|
||||||
|
<div
|
||||||
|
v-for="block in blocks"
|
||||||
|
:key="block.uuid"
|
||||||
|
class="cursor-move border rounded p-2 bg-white dark:bg-gray-700 shadow hover:bg-gray-50 dark:hover:bg-gray-600"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="handleDragStart($event, block)"
|
||||||
|
>
|
||||||
|
<span class="block text-xs font-medium text-gray-900 dark:text-white">{{ block.description }}</span>
|
||||||
|
<img :src="block.thumbUrl" class="mt-2 w-full object-cover rounded" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.collapse {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
</style>
|
23
resources/js/components/Blocks/BlockPreviewer.vue
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<script setup>
|
||||||
|
import { defineProps } from 'vue';
|
||||||
|
|
||||||
|
// Import all block components explicitly
|
||||||
|
|
||||||
|
const { block } = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<component :is="components[block.componentName]" :block="block" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Optional styles */
|
||||||
|
</style>
|
128
resources/js/components/Blocks/BlockWrapper.vue
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import Icon from '@/Components/Icon.vue'
|
||||||
|
|
||||||
|
import HeroLogoText from '@/Components/Blocks/Heroes/HeroLogoText.vue';
|
||||||
|
import HeroLogoTextOptions from '@/Components/Blocks/Heroes/HeroLogoTextOptions.vue';
|
||||||
|
|
||||||
|
import FAQList from '@/Components/Blocks/FAQ/FAQList.vue';
|
||||||
|
import FAQListOptions from '@/Components/Blocks/FAQ/FAQListOptions.vue';
|
||||||
|
import FAQCollapse from '@/Components/Blocks/FAQ/FAQCollapse.vue';
|
||||||
|
import FAQCollapseOptions from '@/Components/Blocks/FAQ/FAQCollapseOptions.vue';
|
||||||
|
import FAQCondensed from '@/Components/Blocks/FAQ/FAQCondensed.vue';
|
||||||
|
import FAQCondensedOptions from '@/Components/Blocks/FAQ/FAQCondensedOptions.vue';
|
||||||
|
|
||||||
|
import TwoColumnText from '@/Components/Blocks/Text/TwoColumnText.vue';
|
||||||
|
import TwoColumnTextOptions from '@/Components/Blocks/Text/TwoColumnTextOptions.vue';
|
||||||
|
|
||||||
|
import FrontPageMenuHeader from '@/Components/Blocks/Statics/FrontPageMenuHeader.vue';
|
||||||
|
import FrontPageMenuHeaderOptions from '@/Components/Blocks/Statics/FrontPageMenuHeaderOptions.vue';
|
||||||
|
import FrontPageSponsors from '@/Components/Blocks/Statics/FrontPageSponsors.vue';
|
||||||
|
import FrontPageSponsorsOptions from '@/Components/Blocks/Statics/FrontPageSponsorsOptions.vue';
|
||||||
|
import FrontPageMembershipInfo from '@/Components/Blocks/Statics/FrontPageMembershipInfo.vue';
|
||||||
|
import FrontPageMembershipInfoOptions from '@/Components/Blocks/Statics/FrontPageMembershipInfoOptions.vue';
|
||||||
|
import FrontPageNewsList from '@/Components/Blocks/Statics/FrontPageNewsList.vue';
|
||||||
|
import FrontPageNewsListOptions from '@/Components/Blocks/Statics/FrontPageNewsListOptions.vue';
|
||||||
|
import FrontPageEventsList from '@/Components/Blocks/Statics/FrontPageEventsList.vue';
|
||||||
|
import FrontPageEventsListOptions from '@/Components/Blocks/Statics/FrontPageEventsListOptions.vue';
|
||||||
|
|
||||||
|
import PageFooter from '@/Components/Blocks/Statics/PageFooter.vue';
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
HeroLogoText,
|
||||||
|
HeroLogoTextOptions,
|
||||||
|
FAQList,
|
||||||
|
FAQListOptions,
|
||||||
|
FAQCollapse,
|
||||||
|
FAQCollapseOptions,
|
||||||
|
FAQCondensed,
|
||||||
|
FAQCondensedOptions,
|
||||||
|
TwoColumnText,
|
||||||
|
TwoColumnTextOptions,
|
||||||
|
FrontPageMenuHeader,
|
||||||
|
FrontPageMenuHeaderOptions,
|
||||||
|
FrontPageSponsors,
|
||||||
|
FrontPageSponsorsOptions,
|
||||||
|
FrontPageMembershipInfo,
|
||||||
|
FrontPageMembershipInfoOptions,
|
||||||
|
FrontPageNewsList,
|
||||||
|
FrontPageNewsListOptions,
|
||||||
|
FrontPageEventsList,
|
||||||
|
FrontPageEventsListOptions,
|
||||||
|
PageFooter
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
images: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['delete']);
|
||||||
|
|
||||||
|
const showDrawer = ref(false);
|
||||||
|
|
||||||
|
const toggleDrawer = () => {
|
||||||
|
showDrawer.value = !showDrawer.value;
|
||||||
|
emit('drawer-state', showDrawer.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isStatic = computed(() => props.block.static === true);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="relative group border rounded-md p-4 bg-black dark:bg-gray-800">
|
||||||
|
<!-- Render the actual block -->
|
||||||
|
<component :images="images" :is="components[block.componentName]" :block="block" />
|
||||||
|
|
||||||
|
<!-- Floating toolbar -->
|
||||||
|
<div class="absolute top-0 left-0 flex flex-col space-y-1 p-1 bg-gray-700 rounded-tr-md rounded-br-md text-white z-10">
|
||||||
|
<!-- Drag handle -->
|
||||||
|
<div class="cursor-move handle p-1 hover:bg-gray-600 rounded">
|
||||||
|
<Icon name="move" class="h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Open options drawer -->
|
||||||
|
<button :disabled="isStatic" @click="toggleDrawer" class="p-1 hover:bg-gray-600 rounded">
|
||||||
|
<Icon name="settings" class="h-4 w-4" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Delete block -->
|
||||||
|
<button @click="emit('delete')" class="p-1 hover:bg-red-600 text-red-300 rounded">
|
||||||
|
<Icon name="trash" class="h-4 w-4" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Options drawer -->
|
||||||
|
<teleport to="body">
|
||||||
|
<div v-if="showDrawer" class="fixed inset-0 z-50 bg-black/50 flex">
|
||||||
|
<div class="bg-white dark:bg-gray-800 w-96 max-w-full h-full shadow-lg p-4 overflow-y-auto">
|
||||||
|
<div class="flex justify-between items-center mb-4">
|
||||||
|
<h2 class="text-lg font-semibold text-gray-800 dark:text-white">Blokkinnstillinger</h2>
|
||||||
|
<button @click="toggleDrawer" class="text-gray-500 hover:text-red-500 dark:text-gray-300 dark:hover:text-red-400">
|
||||||
|
✕
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<component
|
||||||
|
:is="components[block.optionsComponentName]"
|
||||||
|
:block="block"
|
||||||
|
:images="images"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1" @click="toggleDrawer"></div>
|
||||||
|
</div>
|
||||||
|
</teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Optional styling tweaks */
|
||||||
|
</style>
|
33
resources/js/components/Blocks/FAQ/FAQCollapse.vue
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<script setup>
|
||||||
|
import { defineProps } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const faqs = props.block.faqs || [
|
||||||
|
{ question: 'Hva er dette?', answer: 'Dette er et eksempel på et spørsmål og svar.' },
|
||||||
|
{ question: 'Hvordan fungerer det?', answer: 'Du legger til innhold og publiserer siden.' },
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="relative py-20 md:py-24 overflow-hidden mx-auto max-w-[1280px] bg-black">
|
||||||
|
<div class="container mx-auto px-6 lg:px-20">
|
||||||
|
<h2 class="text-amber-600 text-xl md:text-2xl font-serif mb-6">{{ block.title || 'Vanlige spørsmål' }}</h2>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<details v-for="(faq, index) in faqs" :key="index" class="bg-gray-700 p-4 rounded-md shadow">
|
||||||
|
<summary class="cursor-pointer font-medium text-white">{{ faq.question }}</summary>
|
||||||
|
<p class="mt-2 text-gray-300">{{ faq.answer }}</p>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Optional collapse styles */
|
||||||
|
</style>
|
103
resources/js/components/Blocks/FAQ/FAQCollapseOptions.vue
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<script setup>
|
||||||
|
import Icon from '@/Components/Icon.vue';
|
||||||
|
import { toRef, ref } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:block']);
|
||||||
|
const local = toRef(props, 'block');
|
||||||
|
|
||||||
|
// Drag state
|
||||||
|
const draggedIndex = ref(null);
|
||||||
|
|
||||||
|
function handleDragStart(event, index) {
|
||||||
|
draggedIndex.value = index;
|
||||||
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
event.dataTransfer.setData('text/plain', index);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDragOver(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDrop(event, index) {
|
||||||
|
event.preventDefault();
|
||||||
|
const fromIndex = draggedIndex.value;
|
||||||
|
if (fromIndex === null || fromIndex === index) return;
|
||||||
|
|
||||||
|
const item = local.value.faqs.splice(fromIndex, 1)[0];
|
||||||
|
local.value.faqs.splice(index, 0, item);
|
||||||
|
draggedIndex.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
function addFaq() {
|
||||||
|
local.value.faqs.push({
|
||||||
|
question: '',
|
||||||
|
answer: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFaq(index) {
|
||||||
|
local.value.faqs.splice(index, 1);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tittel for seksjonen</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.title"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div
|
||||||
|
v-for="(faq, index) in local.faqs"
|
||||||
|
:key="index"
|
||||||
|
class="flex items-start gap-2 p-4 rounded border dark:border-gray-600 bg-gray-50 dark:bg-gray-800"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="handleDragStart($event, index)"
|
||||||
|
@dragover="handleDragOver"
|
||||||
|
@drop="handleDrop($event, index)"
|
||||||
|
>
|
||||||
|
<div class="cursor-move mt-1 text-gray-500 dark:text-gray-400">
|
||||||
|
<Icon name="move" class="w-4 h-4" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 space-y-2">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-sm font-semibold text-gray-700 dark:text-gray-300">FAQ {{ index + 1 }}</span>
|
||||||
|
<button @click="removeFaq(index)" class="text-red-500 hover:underline text-xs">Fjern</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400">Spørsmål</label>
|
||||||
|
<input type="text" class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white" v-model="faq.question" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400">Svar</label>
|
||||||
|
<textarea rows="2" class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white" v-model="faq.answer"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button @click="addFaq" class="mt-2 px-4 py-2 bg-blue-600 text-white text-sm rounded hover:bg-blue-700">
|
||||||
|
Legg til ny FAQ
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
33
resources/js/components/Blocks/FAQ/FAQCollapseRendered.vue
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<script setup>
|
||||||
|
import { defineProps } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const faqs = props.block.faqs || [
|
||||||
|
{ question: 'Hva er dette?', answer: 'Dette er et eksempel på et spørsmål og svar.' },
|
||||||
|
{ question: 'Hvordan fungerer det?', answer: 'Du legger til innhold og publiserer siden.' },
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="relative py-20 md:py-24 overflow-hidden mx-auto max-w-[1280px] bg-black">
|
||||||
|
<div class="container mx-auto px-6 lg:px-20">
|
||||||
|
<h2 class="text-amber-600 text-xl md:text-2xl font-serif mb-6">{{ block.title || 'Vanlige spørsmål' }}</h2>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<details v-for="(faq, index) in faqs" :key="index" class="bg-gray-700 p-4 rounded-md shadow">
|
||||||
|
<summary class="cursor-pointer font-medium text-white">{{ faq.question }}</summary>
|
||||||
|
<p class="mt-2 text-gray-300">{{ faq.answer }}</p>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Optional collapse styles */
|
||||||
|
</style>
|
117
resources/js/components/Blocks/FAQ/FAQCondensed.vue
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<script setup>
|
||||||
|
import { defineProps, ref, nextTick, onMounted } from 'vue';
|
||||||
|
import { gsap } from 'gsap';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
import { marked } from 'marked';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
faqs[0].categoryContent[0].state = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
const faqArticleContainer = ref(null);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const faqs = props.block.faqs || [
|
||||||
|
{
|
||||||
|
categoryName: 'Kategori 1',
|
||||||
|
categoryContent: [
|
||||||
|
{ question: 'Spørsmål 1', answer: 'Dette er svar på spørsmål 1', state: false },
|
||||||
|
{ question: 'Spørsmål 2', answer: 'Dette er svar på spørsmål 2', state: false },
|
||||||
|
{ question: 'Spørsmål 3', answer: 'Dette er svar på spørsmål 3', state: false }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
categoryName: 'Kategori 2',
|
||||||
|
categoryContent: [
|
||||||
|
{ question: 'Spørsmål 4', answer: 'Dette er svar på spørsmål 4', state: false },
|
||||||
|
{ question: 'Spørsmål 5', answer: 'Dette er svar på spørsmål 5', state: false },
|
||||||
|
{ question: 'Spørsmål 6', answer: 'Dette er svar på spørsmål 6', state: false }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const setFalseExcept = (categoryIndex, qaIndex) => {
|
||||||
|
faqs.forEach((category, cIdx) => {
|
||||||
|
category.categoryContent.forEach((qa, qIdx) => {
|
||||||
|
qa.state = cIdx === categoryIndex && qIdx === qaIndex;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const showFaq = (categoryIndex, qaIndex) => {
|
||||||
|
gsap.to(faqArticleContainer.value, {y: 200, opacity: 0, onComplete: () => {
|
||||||
|
setFalseExcept(categoryIndex, qaIndex);
|
||||||
|
// Wait for the DOM to update
|
||||||
|
nextTick().then(() => {
|
||||||
|
// Animate new articles in from the right
|
||||||
|
gsap.fromTo(faqArticleContainer.value, {y: 200, opacity: 0}, {y: 0, opacity: 1});
|
||||||
|
});
|
||||||
|
}});
|
||||||
|
};
|
||||||
|
|
||||||
|
const stateOf = (categoryIndex, qaIndex) => {
|
||||||
|
return faqs[categoryIndex].categoryContent[qaIndex]?.state;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="relative py-20 md:py-24 overflow-hidden mx-auto max-w-[1280px] bg-black">
|
||||||
|
<div class="relative container px-4 mx-auto">
|
||||||
|
<div class="max-w-7xl mx-auto">
|
||||||
|
<div class="text-center mb-20">
|
||||||
|
<span v-if="block.showlabel" class="inline-block py-1 px-3 mb-4 text-xs font-semibold text-orange-900 bg-orange-50 rounded-full">
|
||||||
|
{{ block.label || 'Skriv inn en tekst for merkelappen' }}
|
||||||
|
</span>
|
||||||
|
<h1 v-if="block.showtitle" class="font-heading text-5xl xs:text-6xl md:text-7xl font-bold text-gray-500">
|
||||||
|
<span>{{ block.title || 'Overskrift' }} </span>
|
||||||
|
<span class="font-serif italic font-normal">{{ block.titlecursive || 'Overskriftkursiv' }}</span>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-wrap -mx-4 -mb-8">
|
||||||
|
<div class="w-full lg:w-1/3 px-4 mb-15 lg:mb-0">
|
||||||
|
<div class="flex flex-wrap -mx-2 lg:flex-col lg:max-w-sm border-b lg:border-b-0 lg:border-r border-gray-100">
|
||||||
|
<div v-for="(faq, index) in faqs" :key="index" class="w-full md:w-1/2 lg:w-full px-2 mb-15">
|
||||||
|
<h4 class="text-2xl font-semibold mb-6 text-amber-600">{{ faq.categoryName }}</h4>
|
||||||
|
<ul class="mb-6">
|
||||||
|
<li v-for="(category, catIndex) in faq.categoryContent" :key="catIndex" class="mb-6">
|
||||||
|
<button type="button" @click="showFaq(index, catIndex)" class="flex items-center text-lg hover:text-amber-700" :class="stateOf(index, catIndex) ? 'text-amber-700 font-semibold' : 'text-white font-normal'">
|
||||||
|
<svg width="12" height="12" viewbox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="6" cy="6" r="5" stroke="#C3C6CE" stroke-width="2"></circle>
|
||||||
|
</svg>
|
||||||
|
<span class="ml-3">
|
||||||
|
{{ category.question }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-full lg:w-2/3 px-4" ref="faqArticleContainer">
|
||||||
|
<template v-for="(faq, index) in faqs" :key="index">
|
||||||
|
<template v-for="(category, catIndex) in faq.categoryContent" :key="catIndex">
|
||||||
|
<div v-show="stateOf(index, catIndex)" class="max-w-xl xl:max-w-3xl mx-auto lg:mr-0">
|
||||||
|
<h2 class="text-5xl font-semibold text-gray-500 mb-14">{{ category.question }}</h2>
|
||||||
|
<div v-if="category.answer" v-html="marked(category.answer)" class="text-gray-300">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Optional FAQ list styles */
|
||||||
|
</style>
|
285
resources/js/components/Blocks/FAQ/FAQCondensedOptions.vue
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
<script setup>
|
||||||
|
import Icon from '@/Components/Icon.vue'
|
||||||
|
import { ref, toRef, watch } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: { type: Object, required: true }
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:block']);
|
||||||
|
|
||||||
|
const local = toRef(props, 'block');
|
||||||
|
const collapsedCategories = ref([]);
|
||||||
|
|
||||||
|
watch(local, (val) => {
|
||||||
|
emit('update:block', val);
|
||||||
|
}, { deep: true });
|
||||||
|
|
||||||
|
watch(() => local.value.faqs, (faqs) => {
|
||||||
|
if (collapsedCategories.value.length !== faqs.length) {
|
||||||
|
collapsedCategories.value = faqs.map((_, i) =>
|
||||||
|
collapsedCategories.value[i] ?? true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, { immediate: true, deep: true });
|
||||||
|
|
||||||
|
function toggleCategoryCollapse(index) {
|
||||||
|
collapsedCategories.value[index] = !collapsedCategories.value[index];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Drag state for categories
|
||||||
|
const draggedCategoryIndex = ref(null);
|
||||||
|
|
||||||
|
function handleDragStartCategory(event, index) {
|
||||||
|
draggedCategoryIndex.value = index;
|
||||||
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
event.dataTransfer.setData('text/plain', index);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDragOverCategory(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDropCategory(event, index) {
|
||||||
|
event.preventDefault();
|
||||||
|
const fromIndex = draggedCategoryIndex.value;
|
||||||
|
if (fromIndex === null || fromIndex === index) return;
|
||||||
|
|
||||||
|
const item = local.value.faqs.splice(fromIndex, 1)[0];
|
||||||
|
local.value.faqs.splice(index, 0, item);
|
||||||
|
draggedCategoryIndex.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// End drag state categories
|
||||||
|
|
||||||
|
// Add and remove questions
|
||||||
|
function addFaqCategory() {
|
||||||
|
local.value.faqs = local.value.faqs || [];
|
||||||
|
local.value.faqs.push({ categoryName: '', categoryContent: [{}] });
|
||||||
|
};
|
||||||
|
|
||||||
|
function removeFaqCategory(index) {
|
||||||
|
local.value.faqs.splice(index, 1);
|
||||||
|
};
|
||||||
|
// End add and remove categories
|
||||||
|
|
||||||
|
|
||||||
|
// Drag state for questions & answers
|
||||||
|
const draggedQAIndex = ref(null);
|
||||||
|
const draggedCategoryForQA = ref(null);
|
||||||
|
|
||||||
|
function handleDragStartQA(event, indexQA, categoryIndex) {
|
||||||
|
draggedQAIndex.value = indexQA;
|
||||||
|
draggedCategoryForQA.value = categoryIndex;
|
||||||
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
event.dataTransfer.setData('text/plain', indexQA);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragOverQA(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDropQA(event, indexQA, categoryIndex) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const fromIndex = draggedQAIndex.value;
|
||||||
|
const fromCategoryIndex = draggedCategoryForQA.value;
|
||||||
|
|
||||||
|
if (
|
||||||
|
fromIndex === null ||
|
||||||
|
fromCategoryIndex === null ||
|
||||||
|
(fromIndex === indexQA && fromCategoryIndex === categoryIndex)
|
||||||
|
) return;
|
||||||
|
|
||||||
|
const sourceCategory = local.value.faqs[fromCategoryIndex];
|
||||||
|
const targetCategory = local.value.faqs[categoryIndex];
|
||||||
|
|
||||||
|
const item = sourceCategory.categoryContent.splice(fromIndex, 1)[0];
|
||||||
|
targetCategory.categoryContent.splice(indexQA, 0, item);
|
||||||
|
|
||||||
|
draggedQAIndex.value = null;
|
||||||
|
draggedCategoryForQA.value = null;
|
||||||
|
}
|
||||||
|
// End drag state for questions & answers
|
||||||
|
|
||||||
|
// Add and remove questions & answers
|
||||||
|
function addQA(categoryIndex) {
|
||||||
|
local.value.faqs[categoryIndex].categoryContent.push({ question: '', answer: '', state: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeQA(indexQA, categoryIndex) {
|
||||||
|
local.value.faqs[categoryIndex].categoryContent.splice(indexQA, 1);
|
||||||
|
}
|
||||||
|
// End add and remove
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">DOM ID</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.anchorName"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="label-checkbox"
|
||||||
|
aria-describedby="label-checkbox-text"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="local.showlabel"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ms-2 text-sm">
|
||||||
|
<label for="label-checkbox" class="font-medium text-gray-900 dark:text-gray-300">Vis merkelapp</label>
|
||||||
|
<p id="label-checkbox-text" class="text-xs font-normal text-gray-500 dark:text-gray-300">Skru merkelappen øverst på komponenten av, eller på</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Merkelapp tekst</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.label"
|
||||||
|
:disabled="!local.showlabel"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="title-checkbox"
|
||||||
|
aria-describedby="title-checkbox-text"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="local.showtitle"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ms-2 text-sm">
|
||||||
|
<label for="title-checkbox" class="font-medium text-gray-900 dark:text-gray-300">Vis tittel</label>
|
||||||
|
<p id="title-checkbox-text" class="text-xs font-normal text-gray-500 dark:text-gray-300">Skru tittelen på komponenten av, eller på</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tittel tekst</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.title"
|
||||||
|
:disabled="!local.showtitle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tittel kursiv tekst</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.titlecursive"
|
||||||
|
:disabled="!local.showtitle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div
|
||||||
|
v-for="(faq, index) in local.faqs"
|
||||||
|
:key="index"
|
||||||
|
class="flex items-start gap-2 p-4 rounded border dark:border-gray-600 bg-gray-50 dark:bg-gray-800"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="handleDragStartCategory($event, index)"
|
||||||
|
@dragover="handleDragOverCategory"
|
||||||
|
@drop="handleDropCategory($event, index)"
|
||||||
|
>
|
||||||
|
<!-- Drag handle -->
|
||||||
|
<div class="cursor-move mt-1 text-gray-500 dark:text-gray-400">
|
||||||
|
<Icon name="move" class="w-4 h-4" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
|
<div class="flex-1 space-y-2">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-sm font-semibold text-gray-700 dark:text-gray-300">FAQ Kategori {{ index + 1 }}</span>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button
|
||||||
|
@click="toggleCategoryCollapse(index)"
|
||||||
|
class="text-blue-500 text-xs hover:underline"
|
||||||
|
>
|
||||||
|
{{ collapsedCategories[index] ? 'Vis' : 'Skjul' }}
|
||||||
|
</button>
|
||||||
|
<button @click="removeFaqCategory(index)" class="text-red-500 hover:underline text-xs">
|
||||||
|
Fjern
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400">Kategori tittel</label>
|
||||||
|
<input type="text" class="block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white" v-model="faq.categoryName" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-show="!collapsedCategories[index]">
|
||||||
|
<h5 class="text-xs font-semibold text-gray-600 dark:text-gray-400">Spørsmål & Svar</h5>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-for="(qa, indexQA) in faq.categoryContent"
|
||||||
|
:key="indexQA"
|
||||||
|
class="flex items-start mt-2 gap-2 p-4 rounded border dark:border-gray-600 bg-gray-50 dark:bg-gray-800"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="handleDragStartQA($event, indexQA, index)"
|
||||||
|
@dragover="handleDragOverQA"
|
||||||
|
@drop="handleDropQA($event, indexQA, index)"
|
||||||
|
>
|
||||||
|
<!-- Drag handle -->
|
||||||
|
<div class="cursor-move mt-1 text-gray-500 dark:text-gray-400">
|
||||||
|
<Icon name="move" class="w-4 h-4" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 space-y-2">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-sm font-semibold text-gray-700 dark:text-gray-300">"{{ faq.categoryName }}" spørsmål {{ indexQA + 1 }}</span>
|
||||||
|
<button @click="removeQA(indexQA, index)" class="text-red-500 hover:underline text-xs">Fjern</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400">Spørsmål</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
v-model="qa.question"
|
||||||
|
class="block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400">Svar</label>
|
||||||
|
<textarea
|
||||||
|
rows="3"
|
||||||
|
v-model="qa.answer"
|
||||||
|
class="block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
@click="addQA(index)"
|
||||||
|
class="mt-2 px-3 py-1 bg-green-600 text-white text-xs rounded hover:bg-green-700"
|
||||||
|
>
|
||||||
|
Legg til spørsmål & svar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button @click="addFaqCategory" class="mt-2 px-4 py-2 bg-blue-600 text-white text-sm rounded hover:bg-blue-700">
|
||||||
|
Legg til ny kategori
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
117
resources/js/components/Blocks/FAQ/FAQCondensedRendered.vue
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<script setup>
|
||||||
|
import { defineProps, ref, nextTick, onMounted } from 'vue';
|
||||||
|
import { gsap } from 'gsap';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
import { marked } from 'marked';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
faqs[0].categoryContent[0].state = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
const faqArticleContainer = ref(null);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const faqs = props.block.faqs || [
|
||||||
|
{
|
||||||
|
categoryName: 'Kategori 1',
|
||||||
|
categoryContent: [
|
||||||
|
{ question: 'Spørsmål 1', answer: 'Dette er svar på spørsmål 1', state: false },
|
||||||
|
{ question: 'Spørsmål 2', answer: 'Dette er svar på spørsmål 2', state: false },
|
||||||
|
{ question: 'Spørsmål 3', answer: 'Dette er svar på spørsmål 3', state: false }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
categoryName: 'Kategori 2',
|
||||||
|
categoryContent: [
|
||||||
|
{ question: 'Spørsmål 4', answer: 'Dette er svar på spørsmål 4', state: false },
|
||||||
|
{ question: 'Spørsmål 5', answer: 'Dette er svar på spørsmål 5', state: false },
|
||||||
|
{ question: 'Spørsmål 6', answer: 'Dette er svar på spørsmål 6', state: false }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const setFalseExcept = (categoryIndex, qaIndex) => {
|
||||||
|
faqs.forEach((category, cIdx) => {
|
||||||
|
category.categoryContent.forEach((qa, qIdx) => {
|
||||||
|
qa.state = cIdx === categoryIndex && qIdx === qaIndex;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const showFaq = (categoryIndex, qaIndex) => {
|
||||||
|
gsap.to(faqArticleContainer.value, {y: 200, opacity: 0, onComplete: () => {
|
||||||
|
setFalseExcept(categoryIndex, qaIndex);
|
||||||
|
// Wait for the DOM to update
|
||||||
|
nextTick().then(() => {
|
||||||
|
// Animate new articles in from the right
|
||||||
|
gsap.fromTo(faqArticleContainer.value, {y: 200, opacity: 0}, {y: 0, opacity: 1});
|
||||||
|
});
|
||||||
|
}});
|
||||||
|
};
|
||||||
|
|
||||||
|
const stateOf = (categoryIndex, qaIndex) => {
|
||||||
|
return faqs[categoryIndex].categoryContent[qaIndex]?.state;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section :id="block.anchorName" class="relative py-20 md:py-24 overflow-hidden mx-auto max-w-[1280px] bg-black">
|
||||||
|
<div class="relative container px-4 mx-auto">
|
||||||
|
<div class="max-w-7xl mx-auto">
|
||||||
|
<div class="text-center mb-20">
|
||||||
|
<span v-if="block.showlabel" class="inline-block py-1 px-3 mb-4 text-xs font-semibold text-orange-900 bg-orange-50 rounded-full">
|
||||||
|
{{ block.label || 'Skriv inn en tekst for merkelappen' }}
|
||||||
|
</span>
|
||||||
|
<h1 v-if="block.showtitle" class="font-heading text-5xl xs:text-6xl md:text-7xl font-bold text-gray-500">
|
||||||
|
<span>{{ block.title || 'Overskrift' }} </span>
|
||||||
|
<span class="font-serif italic font-normal">{{ block.titlecursive || 'Overskriftkursiv' }}</span>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-wrap -mx-4 -mb-8">
|
||||||
|
<div class="w-full lg:w-1/3 px-4 mb-15 lg:mb-0">
|
||||||
|
<div class="flex flex-wrap -mx-2 lg:flex-col lg:max-w-sm border-b lg:border-b-0 lg:border-r border-gray-100">
|
||||||
|
<div v-for="(faq, index) in faqs" :key="index" class="w-full md:w-1/2 lg:w-full px-2 mb-15">
|
||||||
|
<h4 class="text-2xl font-semibold mb-6 text-amber-600">{{ faq.categoryName }}</h4>
|
||||||
|
<ul class="mb-6">
|
||||||
|
<li v-for="(category, catIndex) in faq.categoryContent" :key="catIndex" class="mb-6">
|
||||||
|
<button type="button" @click="showFaq(index, catIndex)" class="flex items-center text-lg hover:text-amber-700" :class="stateOf(index, catIndex) ? 'text-amber-700 font-semibold' : 'text-white font-normal'">
|
||||||
|
<svg width="12" height="12" viewbox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="6" cy="6" r="5" stroke="#C3C6CE" stroke-width="2"></circle>
|
||||||
|
</svg>
|
||||||
|
<span class="ml-3">
|
||||||
|
{{ category.question }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-full lg:w-2/3 px-4" ref="faqArticleContainer">
|
||||||
|
<template v-for="(faq, index) in faqs" :key="index">
|
||||||
|
<template v-for="(category, catIndex) in faq.categoryContent" :key="catIndex">
|
||||||
|
<div v-show="stateOf(index, catIndex)" class="max-w-xl xl:max-w-3xl mx-auto lg:mr-0">
|
||||||
|
<h2 class="text-5xl font-semibold text-gray-500 mb-14">{{ category.question }}</h2>
|
||||||
|
<div v-if="category.answer" v-html="marked(category.answer)" class="text-gray-300">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Optional FAQ list styles */
|
||||||
|
</style>
|
33
resources/js/components/Blocks/FAQ/FAQList.vue
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<script setup>
|
||||||
|
import { defineProps } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const faqs = props.block.faqs || [
|
||||||
|
{ question: 'Hva er dette?', answer: 'Dette er et eksempel på et spørsmål og svar.' },
|
||||||
|
{ question: 'Hvordan fungerer det?', answer: 'Du legger til innhold og publiserer siden.' },
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="relative py-20 md:py-24 overflow-hidden mx-auto max-w-[1280px] bg-black">
|
||||||
|
<div class="container mx-auto px-6 lg:px-20">
|
||||||
|
<h2 class="text-amber-600 text-xl md:text-2xl font-serif mb-6">{{ block.title || 'Vanlige spørsmål' }}</h2>
|
||||||
|
<ul class="space-y-4">
|
||||||
|
<li v-for="(faq, index) in faqs" :key="index" class="border-b pb-4">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-200">{{ faq.question }}</h3>
|
||||||
|
<p class="text-gray-300">{{ faq.answer }}</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Optional FAQ list styles */
|
||||||
|
</style>
|
99
resources/js/components/Blocks/FAQ/FAQListOptions.vue
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<script setup>
|
||||||
|
import Icon from '@/Components/Icon.vue'
|
||||||
|
import { ref, toRef, watch } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: { type: Object, required: true }
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:block']);
|
||||||
|
|
||||||
|
const local = toRef(props, 'block');
|
||||||
|
|
||||||
|
// Drag state
|
||||||
|
const draggedIndex = ref(null);
|
||||||
|
|
||||||
|
function handleDragStart(event, index) {
|
||||||
|
draggedIndex.value = index;
|
||||||
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
event.dataTransfer.setData('text/plain', index);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDragOver(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDrop(event, index) {
|
||||||
|
event.preventDefault();
|
||||||
|
const fromIndex = draggedIndex.value;
|
||||||
|
if (fromIndex === null || fromIndex === index) return;
|
||||||
|
|
||||||
|
const item = local.value.faqs.splice(fromIndex, 1)[0];
|
||||||
|
local.value.faqs.splice(index, 0, item);
|
||||||
|
draggedIndex.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// End drag state
|
||||||
|
|
||||||
|
watch(local, (val) => {
|
||||||
|
emit('update:block', val);
|
||||||
|
}, { deep: true });
|
||||||
|
|
||||||
|
function addFaq() {
|
||||||
|
local.value.faqs = local.value.faqs || [];
|
||||||
|
local.value.faqs.push({ question: '', answer: '' });
|
||||||
|
};
|
||||||
|
|
||||||
|
function removeFaq(index) {
|
||||||
|
local.value.faqs.splice(index, 1);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tittel for seksjonen</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.title"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div
|
||||||
|
v-for="(faq, index) in local.faqs"
|
||||||
|
:key="index"
|
||||||
|
class="flex items-start gap-2 p-4 rounded border dark:border-gray-600 bg-gray-50 dark:bg-gray-800"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="handleDragStart($event, index)"
|
||||||
|
@dragover="handleDragOver"
|
||||||
|
@drop="handleDrop($event, index)"
|
||||||
|
>
|
||||||
|
<!-- Drag handle -->
|
||||||
|
<div class="cursor-move mt-1 text-gray-500 dark:text-gray-400">
|
||||||
|
<Icon name="move" class="w-4 h-4" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
|
<div class="flex-1 space-y-2">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-sm font-semibold text-gray-700 dark:text-gray-300">FAQ {{ index + 1 }}</span>
|
||||||
|
<button @click="removeFaq(index)" class="text-red-500 hover:underline text-xs">Fjern</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400">Spørsmål</label>
|
||||||
|
<input type="text" class="block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white" v-model="faq.question" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400">Svar</label>
|
||||||
|
<textarea rows="2" class="block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white" v-model="faq.answer"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
33
resources/js/components/Blocks/FAQ/FAQListRendered.vue
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<script setup>
|
||||||
|
import { defineProps } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const faqs = props.block.faqs || [
|
||||||
|
{ question: 'Hva er dette?', answer: 'Dette er et eksempel på et spørsmål og svar.' },
|
||||||
|
{ question: 'Hvordan fungerer det?', answer: 'Du legger til innhold og publiserer siden.' },
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="relative py-20 md:py-24 overflow-hidden mx-auto max-w-[1280px] bg-black">
|
||||||
|
<div class="container mx-auto px-6 lg:px-20">
|
||||||
|
<h2 class="text-amber-600 text-xl md:text-2xl font-serif mb-6">{{ block.title || 'Vanlige spørsmål' }}</h2>
|
||||||
|
<ul class="space-y-4">
|
||||||
|
<li v-for="(faq, index) in faqs" :key="index" class="border-b pb-4">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-200">{{ faq.question }}</h3>
|
||||||
|
<p class="text-gray-300">{{ faq.answer }}</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Optional FAQ list styles */
|
||||||
|
</style>
|
110
resources/js/components/Blocks/Heroes/HeroLogoText.vue
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, defineProps } from 'vue';
|
||||||
|
import { Link, router } from '@inertiajs/vue3';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
import ArcticLogo from '@/Components/ClubLogo.vue';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const texts = props.block.texts || [
|
||||||
|
{ paragraph: 'Trenger du et enkelt og fleksibelt system for å organisere din klubb og klubbaktiviteter, uten å knekke lommeboka? Ønsker du et partnerskap med en utvikler med tilhold i Norge og som er lett tilgjengelig dersom du har behov for oppfølging? Kontakt oss for mer informasjon om hvordan vi kan hjelpe deg og din klubb' }
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="relative py-20 md:py-24 overflow-hidden mx-auto max-w-[1280px] bg-black">
|
||||||
|
<div class="relative container px-4 mx-auto">
|
||||||
|
<div class="max-w-2xl lg:max-w-3xl xl:max-w-5xl xl:pr-20">
|
||||||
|
<h1 v-show="block.showtitle" class="font-heading text-4xl sm:text-5xl lg:text-6xl xl:text-7xl font-bold text-gray-500 mb-10">
|
||||||
|
<span>{{ block.title || 'Overskrift' }} </span>
|
||||||
|
<span class="font-serif italic font-normal">{{ block.titlecursive || 'Overskriftkursiv' }}</span>
|
||||||
|
</h1>
|
||||||
|
<p
|
||||||
|
v-for="(text, index) in texts"
|
||||||
|
:key="index"
|
||||||
|
class="max-w-xl text-base sm:text-xl text-gray-300 font-semibold"
|
||||||
|
:class="{
|
||||||
|
'mt-4': index > 0,
|
||||||
|
'mb-10': index === texts.length - 1
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ text.paragraph }}
|
||||||
|
</p>
|
||||||
|
<div class="lg:flex items-center">
|
||||||
|
<a v-if="props.block.showbutton && props.block.buttonaction === 'none'" class="relative group inline-block mb-12 lg:mb-0 md:mr-10 lg:mr-18 py-4 px-6 text-white font-semibold bg-orange-900 rounded-full overflow-hidden" href="#">
|
||||||
|
<div class="absolute top-0 right-full w-full h-full bg-gray-900 transform group-hover:translate-x-full group-hover:scale-102 transition duration-500"></div>
|
||||||
|
<div class="relative flex items-center justify-center">
|
||||||
|
<span class="mr-4">{{ props.block.buttontext }}</span>
|
||||||
|
<span>
|
||||||
|
<svg width="8" height="12" viewbox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6.83 5.28999L2.59 1.04999C2.49704 0.956266 2.38644 0.881872 2.26458 0.831103C2.14272 0.780334 2.01202 0.754196 1.88 0.754196C1.74799 0.754196 1.61729 0.780334 1.49543 0.831103C1.37357 0.881872 1.26297 0.956266 1.17 1.04999C0.983753 1.23736 0.879211 1.49081 0.879211 1.75499C0.879211 2.01918 0.983753 2.27263 1.17 2.45999L4.71 5.99999L1.17 9.53999C0.983753 9.72736 0.879211 9.98081 0.879211 10.245C0.879211 10.5092 0.983753 10.7626 1.17 10.95C1.26344 11.0427 1.37426 11.116 1.4961 11.1658C1.61794 11.2155 1.7484 11.2408 1.88 11.24C2.01161 11.2408 2.14207 11.2155 2.26391 11.1658C2.38575 11.116 2.49656 11.0427 2.59 10.95L6.83 6.70999C6.92373 6.61703 6.99813 6.50643 7.04889 6.38457C7.09966 6.26271 7.1258 6.13201 7.1258 5.99999C7.1258 5.86798 7.09966 5.73728 7.04889 5.61542C6.99813 5.49356 6.92373 5.38296 6.83 5.28999Z" fill="#FAFBFC"></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a v-else-if="props.block.showbutton && props.block.buttonaction === 'external_link'" class="relative group inline-block mb-12 lg:mb-0 md:mr-10 lg:mr-18 py-4 px-6 text-white font-semibold bg-orange-900 rounded-full overflow-hidden" :href="props.block.buttonlink" target="_new">
|
||||||
|
<div class="absolute top-0 right-full w-full h-full bg-gray-900 transform group-hover:translate-x-full group-hover:scale-102 transition duration-500"></div>
|
||||||
|
<div class="relative flex items-center justify-center">
|
||||||
|
<span class="mr-4">{{ props.block.buttontext }}</span>
|
||||||
|
<span>
|
||||||
|
<svg width="8" height="12" viewbox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6.83 5.28999L2.59 1.04999C2.49704 0.956266 2.38644 0.881872 2.26458 0.831103C2.14272 0.780334 2.01202 0.754196 1.88 0.754196C1.74799 0.754196 1.61729 0.780334 1.49543 0.831103C1.37357 0.881872 1.26297 0.956266 1.17 1.04999C0.983753 1.23736 0.879211 1.49081 0.879211 1.75499C0.879211 2.01918 0.983753 2.27263 1.17 2.45999L4.71 5.99999L1.17 9.53999C0.983753 9.72736 0.879211 9.98081 0.879211 10.245C0.879211 10.5092 0.983753 10.7626 1.17 10.95C1.26344 11.0427 1.37426 11.116 1.4961 11.1658C1.61794 11.2155 1.7484 11.2408 1.88 11.24C2.01161 11.2408 2.14207 11.2155 2.26391 11.1658C2.38575 11.116 2.49656 11.0427 2.59 10.95L6.83 6.70999C6.92373 6.61703 6.99813 6.50643 7.04889 6.38457C7.09966 6.26271 7.1258 6.13201 7.1258 5.99999C7.1258 5.86798 7.09966 5.73728 7.04889 5.61542C6.99813 5.49356 6.92373 5.38296 6.83 5.28999Z" fill="#FAFBFC"></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<Link v-else-if="props.block.showbutton && props.block.buttonaction === 'newslink'" class="relative group inline-block mb-12 lg:mb-0 md:mr-10 lg:mr-18 py-4 px-6 text-white font-semibold bg-orange-900 rounded-full overflow-hidden" :href="route('newsArticle', props.block.buttonlink)">
|
||||||
|
<div class="absolute top-0 right-full w-full h-full bg-gray-900 transform group-hover:translate-x-full group-hover:scale-102 transition duration-500"></div>
|
||||||
|
<div class="relative flex items-center justify-center">
|
||||||
|
<span class="mr-4">{{ props.block.buttontext }}</span>
|
||||||
|
<span>
|
||||||
|
<svg width="8" height="12" viewbox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6.83 5.28999L2.59 1.04999C2.49704 0.956266 2.38644 0.881872 2.26458 0.831103C2.14272 0.780334 2.01202 0.754196 1.88 0.754196C1.74799 0.754196 1.61729 0.780334 1.49543 0.831103C1.37357 0.881872 1.26297 0.956266 1.17 1.04999C0.983753 1.23736 0.879211 1.49081 0.879211 1.75499C0.879211 2.01918 0.983753 2.27263 1.17 2.45999L4.71 5.99999L1.17 9.53999C0.983753 9.72736 0.879211 9.98081 0.879211 10.245C0.879211 10.5092 0.983753 10.7626 1.17 10.95C1.26344 11.0427 1.37426 11.116 1.4961 11.1658C1.61794 11.2155 1.7484 11.2408 1.88 11.24C2.01161 11.2408 2.14207 11.2155 2.26391 11.1658C2.38575 11.116 2.49656 11.0427 2.59 10.95L6.83 6.70999C6.92373 6.61703 6.99813 6.50643 7.04889 6.38457C7.09966 6.26271 7.1258 6.13201 7.1258 5.99999C7.1258 5.86798 7.09966 5.73728 7.04889 5.61542C6.99813 5.49356 6.92373 5.38296 6.83 5.28999Z" fill="#FAFBFC"></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
<Link v-else-if="props.block.showbutton && props.block.buttonaction === 'eventlink'" class="relative group inline-block mb-12 lg:mb-0 md:mr-10 lg:mr-18 py-4 px-6 text-white font-semibold bg-orange-900 rounded-full overflow-hidden" :href="route('event', props.block.buttonlink)">
|
||||||
|
<div class="absolute top-0 right-full w-full h-full bg-gray-900 transform group-hover:translate-x-full group-hover:scale-102 transition duration-500"></div>
|
||||||
|
<div class="relative flex items-center justify-center">
|
||||||
|
<span class="mr-4">{{ props.block.buttontext }}</span>
|
||||||
|
<span>
|
||||||
|
<svg width="8" height="12" viewbox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6.83 5.28999L2.59 1.04999C2.49704 0.956266 2.38644 0.881872 2.26458 0.831103C2.14272 0.780334 2.01202 0.754196 1.88 0.754196C1.74799 0.754196 1.61729 0.780334 1.49543 0.831103C1.37357 0.881872 1.26297 0.956266 1.17 1.04999C0.983753 1.23736 0.879211 1.49081 0.879211 1.75499C0.879211 2.01918 0.983753 2.27263 1.17 2.45999L4.71 5.99999L1.17 9.53999C0.983753 9.72736 0.879211 9.98081 0.879211 10.245C0.879211 10.5092 0.983753 10.7626 1.17 10.95C1.26344 11.0427 1.37426 11.116 1.4961 11.1658C1.61794 11.2155 1.7484 11.2408 1.88 11.24C2.01161 11.2408 2.14207 11.2155 2.26391 11.1658C2.38575 11.116 2.49656 11.0427 2.59 10.95L6.83 6.70999C6.92373 6.61703 6.99813 6.50643 7.04889 6.38457C7.09966 6.26271 7.1258 6.13201 7.1258 5.99999C7.1258 5.86798 7.09966 5.73728 7.04889 5.61542C6.99813 5.49356 6.92373 5.38296 6.83 5.28999Z" fill="#FAFBFC"></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
<Link v-else-if="props.block.showbutton && props.block.buttonaction === 'pagelink'" class="relative group inline-block mb-12 lg:mb-0 md:mr-10 lg:mr-18 py-4 px-6 text-white font-semibold bg-orange-900 rounded-full overflow-hidden" :href="route('page.view', props.block.buttonlink)">
|
||||||
|
<div class="absolute top-0 right-full w-full h-full bg-gray-900 transform group-hover:translate-x-full group-hover:scale-102 transition duration-500"></div>
|
||||||
|
<div class="relative flex items-center justify-center">
|
||||||
|
<span class="mr-4">{{ props.block.buttontext }}</span>
|
||||||
|
<span>
|
||||||
|
<svg width="8" height="12" viewbox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6.83 5.28999L2.59 1.04999C2.49704 0.956266 2.38644 0.881872 2.26458 0.831103C2.14272 0.780334 2.01202 0.754196 1.88 0.754196C1.74799 0.754196 1.61729 0.780334 1.49543 0.831103C1.37357 0.881872 1.26297 0.956266 1.17 1.04999C0.983753 1.23736 0.879211 1.49081 0.879211 1.75499C0.879211 2.01918 0.983753 2.27263 1.17 2.45999L4.71 5.99999L1.17 9.53999C0.983753 9.72736 0.879211 9.98081 0.879211 10.245C0.879211 10.5092 0.983753 10.7626 1.17 10.95C1.26344 11.0427 1.37426 11.116 1.4961 11.1658C1.61794 11.2155 1.7484 11.2408 1.88 11.24C2.01161 11.2408 2.14207 11.2155 2.26391 11.1658C2.38575 11.116 2.49656 11.0427 2.59 10.95L6.83 6.70999C6.92373 6.61703 6.99813 6.50643 7.04889 6.38457C7.09966 6.26271 7.1258 6.13201 7.1258 5.99999C7.1258 5.86798 7.09966 5.73728 7.04889 5.61542C6.99813 5.49356 6.92373 5.38296 6.83 5.28999Z" fill="#FAFBFC"></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
<div v-show="props.block.showlogo" class="flex items-center">
|
||||||
|
<ArcticLogo class="w-14 h-14" />
|
||||||
|
<div class="flex-col items-center justify-center text-center">
|
||||||
|
<p class="font-topsecret text-white text-lg ml-2">Østfold Milsim</p>
|
||||||
|
<p class="font-topsecret text-white text-lg ml-2">Airsoftklubb</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
226
resources/js/components/Blocks/Heroes/HeroLogoTextOptions.vue
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
<script setup>
|
||||||
|
import Icon from '@/Components/Icon.vue';
|
||||||
|
import { toRef, ref, onMounted } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:block']);
|
||||||
|
const local = toRef(props, 'block');
|
||||||
|
|
||||||
|
// Drag state for paragraphs
|
||||||
|
const draggedIndex = ref(null);
|
||||||
|
|
||||||
|
function handleDragStart(event, index) {
|
||||||
|
draggedIndex.value = index;
|
||||||
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
event.dataTransfer.setData('text/plain', index);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDragOver(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDrop(event, index) {
|
||||||
|
event.preventDefault();
|
||||||
|
const fromIndex = draggedIndex.value;
|
||||||
|
if (fromIndex === null || fromIndex === index) return;
|
||||||
|
|
||||||
|
const item = local.value.texts.splice(fromIndex, 1)[0];
|
||||||
|
local.value.texts.splice(index, 0, item);
|
||||||
|
draggedIndex.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
function add() {
|
||||||
|
local.value.texts.push({
|
||||||
|
paragraph: ''
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function remove(index) {
|
||||||
|
local.value.texts.splice(index, 1);
|
||||||
|
}
|
||||||
|
// End drag state functions for paragraphs
|
||||||
|
|
||||||
|
const texts = props.block.texts || [
|
||||||
|
{ paragraph: 'Trenger du et enkelt og fleksibelt system for å organisere din klubb og klubbaktiviteter, uten å knekke lommeboka? Ønsker du et partnerskap med en utvikler med tilhold i Norge og som er lett tilgjengelig dersom du har behov for oppfølging? Kontakt oss for mer informasjon om hvordan vi kan hjelpe deg og din klubb' }
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">DOM ID</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.anchorName"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="title-checkbox"
|
||||||
|
aria-describedby="title-checkbox-text"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="local.showtitle"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ms-2 text-sm">
|
||||||
|
<label for="title-checkbox" class="font-medium text-gray-900 dark:text-gray-300">Vis tittel</label>
|
||||||
|
<p id="title-checkbox-text" class="text-xs font-normal text-gray-500 dark:text-gray-300">Skru tittelen på komponenten av, eller på</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tittel tekst</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.title"
|
||||||
|
:disabled="!local.showtitle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tittel kursiv tekst</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.titlecursive"
|
||||||
|
:disabled="!local.showtitle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="button-checkbox"
|
||||||
|
aria-describedby="button-checkbox-text"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="local.showbutton"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ms-2 text-sm">
|
||||||
|
<label for="button-checkbox" class="font-medium text-gray-900 dark:text-gray-300">Vis knapp</label>
|
||||||
|
<p id="button-checkbox-text" class="text-xs font-normal text-gray-500 dark:text-gray-300">Skru handlingsknappen for komponenten av, eller på</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tittel knapp</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.buttontext"
|
||||||
|
:disabled="!local.showbutton"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label for="actiontype" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Velg knapp handling</label>
|
||||||
|
<select
|
||||||
|
id="actiontype"
|
||||||
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||||
|
v-model="local.buttonaction"
|
||||||
|
:disabled="!local.showbutton"
|
||||||
|
>
|
||||||
|
<option value="none">Inaktiv</option>
|
||||||
|
<option value="newslink">Lenke til nyhetsartikkel</option>
|
||||||
|
<option value="eventlink">Lenke til arrangement</option>
|
||||||
|
<option value="pagelink">Lenke til en annen side</option>
|
||||||
|
<option value="external_link">Ekstern lenke</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div v-show="local.buttonaction != 'none'" class="mb-2">
|
||||||
|
<label for="address-text" class="block mb-2 text-sm font-medium text-gray-700 dark:text-gray-300">Adresse</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
id="address-text"
|
||||||
|
aria-describedby="address-text-explanation"
|
||||||
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||||
|
:placeholder="local.buttonaction === 'newslink' ? 'slug-til-nyhetsartikkel'
|
||||||
|
: local.buttonaction === 'eventlink' ? 'slug-til-arrangement'
|
||||||
|
: local.buttonaction === 'pagelink' ? 'slug-til-side'
|
||||||
|
: local.buttonaction === 'external_link' ? 'https://ekstern.lenke.no'
|
||||||
|
: ''"
|
||||||
|
:disabled="!local.showbutton"
|
||||||
|
v-model="local.buttonlink"
|
||||||
|
>
|
||||||
|
<p id="address-text-explanation" class="mt-2 text-sm text-gray-500 dark:text-gray-400">Skriv inn enten identifikatoren (slug) til den interne lenken, eller full nettsideadresse hvis det er en ekstern lenke</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="logo-checkbox"
|
||||||
|
aria-describedby="logo-checkbox-text"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="local.showlogo"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ms-2 text-sm">
|
||||||
|
<label for="logo-checkbox" class="font-medium text-gray-900 dark:text-gray-300">Vis logo</label>
|
||||||
|
<p id="logo-checkbox-text" class="text-xs font-normal text-gray-500 dark:text-gray-300">Skru logovisning i komponenten av, eller på</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<h3 class="font-bold text-sm text-gray-800 dark:text-white">
|
||||||
|
Tekstparagrafer
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div
|
||||||
|
v-for="(text, index) in local.texts"
|
||||||
|
:key="index"
|
||||||
|
class="flex items-start gap-2 p-4 rounded border dark:border-gray-600 bg-gray-50 dark:bg-gray-800"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="handleDragStart($event, index)"
|
||||||
|
@dragover="handleDragOver"
|
||||||
|
@drop="handleDrop($event, index)"
|
||||||
|
>
|
||||||
|
<div class="cursor-move mt-1 text-gray-500 dark:text-gray-400">
|
||||||
|
<Icon name="move" class="w-4 h-4" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 space-y-2">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-sm font-semibold text-gray-700 dark:text-gray-300">Paragraf {{ index + 1 }}</span>
|
||||||
|
<button @click="remove(index)" class="text-red-500 hover:underline text-xs">Fjern</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400">Tekst</label>
|
||||||
|
<textarea rows="2" class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white" v-model="text.paragraph"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button @click="add" class="mt-2 px-4 py-2 bg-blue-600 text-white text-sm rounded hover:bg-blue-700">
|
||||||
|
Legg til ny paragraf
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Optional FAQ list styles */
|
||||||
|
</style>
|
110
resources/js/components/Blocks/Heroes/HeroLogoTextRendered.vue
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, defineProps } from 'vue';
|
||||||
|
import { Link, router } from '@inertiajs/vue3';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
import ArcticLogo from '@/Components/ArcticFooterLogo.vue';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const texts = props.block.texts || [
|
||||||
|
{ paragraph: 'Trenger du et enkelt og fleksibelt system for å organisere din klubb og klubbaktiviteter, uten å knekke lommeboka? Ønsker du et partnerskap med en utvikler med tilhold i Norge og som er lett tilgjengelig dersom du har behov for oppfølging? Kontakt oss for mer informasjon om hvordan vi kan hjelpe deg og din klubb' }
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section :id="block.anchorName" class="relative py-20 md:py-24 overflow-hidden mx-auto max-w-[1280px] bg-black">
|
||||||
|
<div class="relative container px-4 mx-auto">
|
||||||
|
<div class="max-w-2xl lg:max-w-3xl xl:max-w-5xl xl:pr-20">
|
||||||
|
<h1 v-show="block.showtitle" class="font-heading text-4xl sm:text-5xl lg:text-6xl xl:text-7xl font-bold text-gray-500 mb-10">
|
||||||
|
<span>{{ block.title || 'Overskrift' }} </span>
|
||||||
|
<span class="font-serif italic font-normal">{{ block.titlecursive || 'Overskriftkursiv' }}</span>
|
||||||
|
</h1>
|
||||||
|
<p
|
||||||
|
v-for="(text, index) in texts"
|
||||||
|
:key="index"
|
||||||
|
class="max-w-xl text-base sm:text-xl text-gray-300 font-semibold"
|
||||||
|
:class="{
|
||||||
|
'mt-4': index > 0,
|
||||||
|
'mb-10': index === texts.length - 1
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ text.paragraph }}
|
||||||
|
</p>
|
||||||
|
<div class="lg:flex items-center">
|
||||||
|
<a v-if="props.block.showbutton && props.block.buttonaction === 'none'" class="relative group inline-block mb-12 lg:mb-0 md:mr-10 lg:mr-18 py-4 px-6 text-white font-semibold bg-orange-900 rounded-full overflow-hidden" href="#">
|
||||||
|
<div class="absolute top-0 right-full w-full h-full bg-gray-900 transform group-hover:translate-x-full group-hover:scale-102 transition duration-500"></div>
|
||||||
|
<div class="relative flex items-center justify-center">
|
||||||
|
<span class="mr-4">{{ props.block.buttontext }}</span>
|
||||||
|
<span>
|
||||||
|
<svg width="8" height="12" viewbox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6.83 5.28999L2.59 1.04999C2.49704 0.956266 2.38644 0.881872 2.26458 0.831103C2.14272 0.780334 2.01202 0.754196 1.88 0.754196C1.74799 0.754196 1.61729 0.780334 1.49543 0.831103C1.37357 0.881872 1.26297 0.956266 1.17 1.04999C0.983753 1.23736 0.879211 1.49081 0.879211 1.75499C0.879211 2.01918 0.983753 2.27263 1.17 2.45999L4.71 5.99999L1.17 9.53999C0.983753 9.72736 0.879211 9.98081 0.879211 10.245C0.879211 10.5092 0.983753 10.7626 1.17 10.95C1.26344 11.0427 1.37426 11.116 1.4961 11.1658C1.61794 11.2155 1.7484 11.2408 1.88 11.24C2.01161 11.2408 2.14207 11.2155 2.26391 11.1658C2.38575 11.116 2.49656 11.0427 2.59 10.95L6.83 6.70999C6.92373 6.61703 6.99813 6.50643 7.04889 6.38457C7.09966 6.26271 7.1258 6.13201 7.1258 5.99999C7.1258 5.86798 7.09966 5.73728 7.04889 5.61542C6.99813 5.49356 6.92373 5.38296 6.83 5.28999Z" fill="#FAFBFC"></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a v-else-if="props.block.showbutton && props.block.buttonaction === 'external_link'" class="relative group inline-block mb-12 lg:mb-0 md:mr-10 lg:mr-18 py-4 px-6 text-white font-semibold bg-orange-900 rounded-full overflow-hidden" :href="props.block.buttonlink" target="_new">
|
||||||
|
<div class="absolute top-0 right-full w-full h-full bg-gray-900 transform group-hover:translate-x-full group-hover:scale-102 transition duration-500"></div>
|
||||||
|
<div class="relative flex items-center justify-center">
|
||||||
|
<span class="mr-4">{{ props.block.buttontext }}</span>
|
||||||
|
<span>
|
||||||
|
<svg width="8" height="12" viewbox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6.83 5.28999L2.59 1.04999C2.49704 0.956266 2.38644 0.881872 2.26458 0.831103C2.14272 0.780334 2.01202 0.754196 1.88 0.754196C1.74799 0.754196 1.61729 0.780334 1.49543 0.831103C1.37357 0.881872 1.26297 0.956266 1.17 1.04999C0.983753 1.23736 0.879211 1.49081 0.879211 1.75499C0.879211 2.01918 0.983753 2.27263 1.17 2.45999L4.71 5.99999L1.17 9.53999C0.983753 9.72736 0.879211 9.98081 0.879211 10.245C0.879211 10.5092 0.983753 10.7626 1.17 10.95C1.26344 11.0427 1.37426 11.116 1.4961 11.1658C1.61794 11.2155 1.7484 11.2408 1.88 11.24C2.01161 11.2408 2.14207 11.2155 2.26391 11.1658C2.38575 11.116 2.49656 11.0427 2.59 10.95L6.83 6.70999C6.92373 6.61703 6.99813 6.50643 7.04889 6.38457C7.09966 6.26271 7.1258 6.13201 7.1258 5.99999C7.1258 5.86798 7.09966 5.73728 7.04889 5.61542C6.99813 5.49356 6.92373 5.38296 6.83 5.28999Z" fill="#FAFBFC"></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<Link v-else-if="props.block.showbutton && props.block.buttonaction === 'newslink'" class="relative group inline-block mb-12 lg:mb-0 md:mr-10 lg:mr-18 py-4 px-6 text-white font-semibold bg-orange-900 rounded-full overflow-hidden" :href="route('newsArticle', props.block.buttonlink)">
|
||||||
|
<div class="absolute top-0 right-full w-full h-full bg-gray-900 transform group-hover:translate-x-full group-hover:scale-102 transition duration-500"></div>
|
||||||
|
<div class="relative flex items-center justify-center">
|
||||||
|
<span class="mr-4">{{ props.block.buttontext }}</span>
|
||||||
|
<span>
|
||||||
|
<svg width="8" height="12" viewbox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6.83 5.28999L2.59 1.04999C2.49704 0.956266 2.38644 0.881872 2.26458 0.831103C2.14272 0.780334 2.01202 0.754196 1.88 0.754196C1.74799 0.754196 1.61729 0.780334 1.49543 0.831103C1.37357 0.881872 1.26297 0.956266 1.17 1.04999C0.983753 1.23736 0.879211 1.49081 0.879211 1.75499C0.879211 2.01918 0.983753 2.27263 1.17 2.45999L4.71 5.99999L1.17 9.53999C0.983753 9.72736 0.879211 9.98081 0.879211 10.245C0.879211 10.5092 0.983753 10.7626 1.17 10.95C1.26344 11.0427 1.37426 11.116 1.4961 11.1658C1.61794 11.2155 1.7484 11.2408 1.88 11.24C2.01161 11.2408 2.14207 11.2155 2.26391 11.1658C2.38575 11.116 2.49656 11.0427 2.59 10.95L6.83 6.70999C6.92373 6.61703 6.99813 6.50643 7.04889 6.38457C7.09966 6.26271 7.1258 6.13201 7.1258 5.99999C7.1258 5.86798 7.09966 5.73728 7.04889 5.61542C6.99813 5.49356 6.92373 5.38296 6.83 5.28999Z" fill="#FAFBFC"></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
<Link v-else-if="props.block.showbutton && props.block.buttonaction === 'eventlink'" class="relative group inline-block mb-12 lg:mb-0 md:mr-10 lg:mr-18 py-4 px-6 text-white font-semibold bg-orange-900 rounded-full overflow-hidden" :href="route('event', props.block.buttonlink)">
|
||||||
|
<div class="absolute top-0 right-full w-full h-full bg-gray-900 transform group-hover:translate-x-full group-hover:scale-102 transition duration-500"></div>
|
||||||
|
<div class="relative flex items-center justify-center">
|
||||||
|
<span class="mr-4">{{ props.block.buttontext }}</span>
|
||||||
|
<span>
|
||||||
|
<svg width="8" height="12" viewbox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6.83 5.28999L2.59 1.04999C2.49704 0.956266 2.38644 0.881872 2.26458 0.831103C2.14272 0.780334 2.01202 0.754196 1.88 0.754196C1.74799 0.754196 1.61729 0.780334 1.49543 0.831103C1.37357 0.881872 1.26297 0.956266 1.17 1.04999C0.983753 1.23736 0.879211 1.49081 0.879211 1.75499C0.879211 2.01918 0.983753 2.27263 1.17 2.45999L4.71 5.99999L1.17 9.53999C0.983753 9.72736 0.879211 9.98081 0.879211 10.245C0.879211 10.5092 0.983753 10.7626 1.17 10.95C1.26344 11.0427 1.37426 11.116 1.4961 11.1658C1.61794 11.2155 1.7484 11.2408 1.88 11.24C2.01161 11.2408 2.14207 11.2155 2.26391 11.1658C2.38575 11.116 2.49656 11.0427 2.59 10.95L6.83 6.70999C6.92373 6.61703 6.99813 6.50643 7.04889 6.38457C7.09966 6.26271 7.1258 6.13201 7.1258 5.99999C7.1258 5.86798 7.09966 5.73728 7.04889 5.61542C6.99813 5.49356 6.92373 5.38296 6.83 5.28999Z" fill="#FAFBFC"></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
<Link v-else-if="props.block.showbutton && props.block.buttonaction === 'pagelink'" class="relative group inline-block mb-12 lg:mb-0 md:mr-10 lg:mr-18 py-4 px-6 text-white font-semibold bg-orange-900 rounded-full overflow-hidden" :href="route('page.view', props.block.buttonlink)">
|
||||||
|
<div class="absolute top-0 right-full w-full h-full bg-gray-900 transform group-hover:translate-x-full group-hover:scale-102 transition duration-500"></div>
|
||||||
|
<div class="relative flex items-center justify-center">
|
||||||
|
<span class="mr-4">{{ props.block.buttontext }}</span>
|
||||||
|
<span>
|
||||||
|
<svg width="8" height="12" viewbox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6.83 5.28999L2.59 1.04999C2.49704 0.956266 2.38644 0.881872 2.26458 0.831103C2.14272 0.780334 2.01202 0.754196 1.88 0.754196C1.74799 0.754196 1.61729 0.780334 1.49543 0.831103C1.37357 0.881872 1.26297 0.956266 1.17 1.04999C0.983753 1.23736 0.879211 1.49081 0.879211 1.75499C0.879211 2.01918 0.983753 2.27263 1.17 2.45999L4.71 5.99999L1.17 9.53999C0.983753 9.72736 0.879211 9.98081 0.879211 10.245C0.879211 10.5092 0.983753 10.7626 1.17 10.95C1.26344 11.0427 1.37426 11.116 1.4961 11.1658C1.61794 11.2155 1.7484 11.2408 1.88 11.24C2.01161 11.2408 2.14207 11.2155 2.26391 11.1658C2.38575 11.116 2.49656 11.0427 2.59 10.95L6.83 6.70999C6.92373 6.61703 6.99813 6.50643 7.04889 6.38457C7.09966 6.26271 7.1258 6.13201 7.1258 5.99999C7.1258 5.86798 7.09966 5.73728 7.04889 5.61542C6.99813 5.49356 6.92373 5.38296 6.83 5.28999Z" fill="#FAFBFC"></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
<div v-show="props.block.showlogo" class="flex items-center">
|
||||||
|
<ArcticLogo class="w-14 h-14" />
|
||||||
|
<div class="flex-col items-center justify-center text-center">
|
||||||
|
<p class="font-topsecret text-white text-lg ml-2">Østfold Milsim</p>
|
||||||
|
<p class="font-topsecret text-white text-lg ml-2">Airsoftklubb</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
@ -0,0 +1,85 @@
|
|||||||
|
<script setup>
|
||||||
|
import { defineProps } from 'vue';
|
||||||
|
import { usePage } from '@inertiajs/vue3';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const page = usePage();
|
||||||
|
|
||||||
|
const events = [
|
||||||
|
{
|
||||||
|
headline: 'Familiekveld hos ENHET',
|
||||||
|
text: 'Ta med familien for en hyggelig kveld med mat, drikke og underholdning.',
|
||||||
|
time: '15/04/2025, klokken 12:31'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headline: 'ENHETs Veldedighetsløp for Lokalsamfunnet',
|
||||||
|
text: 'Dette arrangementet kombinerer fysisk aktivitet med en god sak. ENHETs spillere og støttespillere samles for å løpe en forhåndsbestemt distanse.',
|
||||||
|
time: '22/04/2025, klokken 12:31'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headline: 'Bli Med på ENHETs Fotballklinikk for Barn',
|
||||||
|
text: 'En helg dedikert til å lære opp unge fotballspillere med trenere og spillere fra ENHET. Barn i alderen 6-14 år inviteres til å delta i treningsøkter hvor de kan forbedre sine fotballferdigheter, lære om teamarbeid og sportsånd, og ha det gøy',
|
||||||
|
time: '29/04/2025, klokken 12:31'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headline: 'ENHET Fanfest og Sesongkickoff',
|
||||||
|
text: 'En fest for å markere starten på den nye fotballsesongen, hvor fansen kan samles for å feire starten på en ny jakt på seier. Arrangementet kan inkludere live musikk, matboder fra lokale leverandører, autografsignering med spillere, og avduking av ENHET...',
|
||||||
|
time: '06/05/2025, klokken 12:31'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="relative block w-full h-screen overflow-hidden">
|
||||||
|
<div class="absolute inset-0 bg-cover" :style="{ backgroundImage: `url('${block.image}')` }"></div>
|
||||||
|
<div class="absolute inset-0 bg-black opacity-80"></div>
|
||||||
|
<div class="absolute p-12 w-full overflow-auto" style="top: 0; bottom: 0;">
|
||||||
|
<div class="flex-row justify-center items-center">
|
||||||
|
<h1 v-if="block.showtitle" class="text-center text-white font-arctic text-2xl md:text-4xl">{{ block.title || 'Tittel' }}</h1>
|
||||||
|
<h2 v-if="block.showlabel" class="text-center text-amber-600 font-serif text-md md:text-xl">{{ block.label || 'Merkelapp' }}</h2>
|
||||||
|
<h3 v-if="block.showsecondarylabel" class="text-center text-gray-400 font-serif text-sm md:text-md">{{ block.secondarylabel || 'Sekundær merkelapp' }}</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mx-auto max-w-[1280px]">
|
||||||
|
<div class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 mt-12">
|
||||||
|
<!-- Begin events loop -->
|
||||||
|
<div
|
||||||
|
v-for="(event, index) in events"
|
||||||
|
:key="index"
|
||||||
|
class="max-w-sm rounded-lg shadow-xl bg-gray-800 border-gray-700 relative"
|
||||||
|
>
|
||||||
|
<div class="relative">
|
||||||
|
<a href="#">
|
||||||
|
<img class="rounded-t-lg" src="/img/blocks/arrangement_placeholder.jpg" alt="Eksempelbilde" />
|
||||||
|
<!-- Badge positioned absolutely within the relative container -->
|
||||||
|
<div class="absolute top-0 right-0 bg-green-100 text-green-800 text-sm md:text-md font-medium me-2 px-2.5 py-0.5 rounded border-green-400 inline-flex items-center justify-center z-20" style="margin: 0.5rem;">
|
||||||
|
Ingen plassrestriksjoner
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="p-5">
|
||||||
|
<a href="#">
|
||||||
|
<h5 class="mb-2 text-2xl font-bold tracking-tight text-white">{{ event.headline }}</h5>
|
||||||
|
</a>
|
||||||
|
<p class="mb-2 text-sm text-green-400">Oppstart: {{ event.time }}</p>
|
||||||
|
<p class="mb-3 font-normal text-gray-400">{{ event.text }}</p>
|
||||||
|
<a href="#" class="inline-flex items-center px-3 py-2 text-sm font-medium text-center text-white rounded-lg focus:ring-4 focus:outline-none bg-green-600 hover:bg-green-700 focus:ring-green-800">
|
||||||
|
Les mer
|
||||||
|
<svg class="rtl:rotate-180 w-3.5 h-3.5 ms-2" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 10">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5h12m0 0L9 1m4 4L9 9"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- End events loop -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
@ -0,0 +1,182 @@
|
|||||||
|
<script setup>
|
||||||
|
import treeview from "vue3-treeview";
|
||||||
|
import "vue3-treeview/dist/style.css";
|
||||||
|
|
||||||
|
import { toRef, watch, reactive, watchEffect, onMounted } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
images: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:block']);
|
||||||
|
const local = toRef(props, 'block');
|
||||||
|
|
||||||
|
watch(local, (val) => emit('update:block', val), { deep: true });
|
||||||
|
|
||||||
|
const treeData = reactive({
|
||||||
|
nodes: {},
|
||||||
|
config: {
|
||||||
|
checkboxes: false,
|
||||||
|
dragAndDrop: false,
|
||||||
|
editable: false,
|
||||||
|
roots: []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function buildTreeNodes(images) {
|
||||||
|
const nodes = {};
|
||||||
|
const roots = [];
|
||||||
|
|
||||||
|
images.forEach(item => {
|
||||||
|
const id = `id${item.id}`
|
||||||
|
nodes[id] = {
|
||||||
|
nodeId: item.id,
|
||||||
|
text: item.name,
|
||||||
|
fs_type: item.fs_type,
|
||||||
|
fs_meta: item.fs_meta,
|
||||||
|
children: images.filter(child => child.parent_id === item.id).map(child => `id${child.id}`),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (item.parent_id === null) roots.push(id);
|
||||||
|
})
|
||||||
|
|
||||||
|
return { nodes, roots };
|
||||||
|
}
|
||||||
|
|
||||||
|
const onNodeClick = (node) => {
|
||||||
|
if (node.fs_type === 'file') {
|
||||||
|
local.value.image = extractMetaValue(node, 'symbolic_name');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
const { nodes, roots } = buildTreeNodes(props.images);
|
||||||
|
treeData.nodes = nodes;
|
||||||
|
treeData.config.roots = roots;
|
||||||
|
});
|
||||||
|
|
||||||
|
function extractMetaValue(node, key) {
|
||||||
|
let meta = JSON.parse(node.fs_meta);
|
||||||
|
return meta[key];
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Anker navn (DOM ID)</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.anchorName"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="title-checkbox"
|
||||||
|
aria-describedby="title-checkbox-text"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="local.showtitle"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ms-2 text-sm">
|
||||||
|
<label for="title-checkbox" class="font-medium text-gray-900 dark:text-gray-300">Vis tittel</label>
|
||||||
|
<p id="title-checkbox-text" class="text-xs font-normal text-gray-500 dark:text-gray-300">Skru tittelen på komponenten av, eller på</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tittel tekst</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.title"
|
||||||
|
:disabled="!local.showtitle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="label-checkbox"
|
||||||
|
aria-describedby="label-checkbox-text"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="local.showlabel"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ms-2 text-sm">
|
||||||
|
<label for="label-checkbox" class="font-medium text-gray-900 dark:text-gray-300">Vis merkelapp</label>
|
||||||
|
<p id="label-checkbox-text" class="text-xs font-normal text-gray-500 dark:text-gray-300">Skru merkelappen øverst på komponenten av, eller på</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Merkelapp tekst</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.label"
|
||||||
|
:disabled="!local.showlabel"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="label-checkbox"
|
||||||
|
aria-describedby="label-checkbox-text"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="local.showsecondarylabel"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ms-2 text-sm">
|
||||||
|
<label for="label-checkbox" class="font-medium text-gray-900 dark:text-gray-300">Vis sekundær merkelapp</label>
|
||||||
|
<p id="label-checkbox-text" class="text-xs font-normal text-gray-500 dark:text-gray-300">Skru den sekundære merkelappen øverst på komponenten av, eller på (denne merkelappen vises bare for ikke innloggede brukere)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Sekundær Merkelapp tekst</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.secondarylabel"
|
||||||
|
:disabled="!local.showsecondarylabel"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Velg bakgrunnsbilde</label>
|
||||||
|
<treeview
|
||||||
|
v-if="images && images.length"
|
||||||
|
@nodeFocus="onNodeClick"
|
||||||
|
:nodes="treeData.nodes"
|
||||||
|
:config="treeData.config"
|
||||||
|
class="mt-4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,193 @@
|
|||||||
|
<script setup>
|
||||||
|
import { defineProps } from 'vue';
|
||||||
|
import { usePage } from '@inertiajs/vue3';
|
||||||
|
import { marked } from 'marked';
|
||||||
|
|
||||||
|
const page = usePage();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="relative block w-full h-screen overflow-hidden">
|
||||||
|
<div class="absolute inset-0 bg-cover" :style="{ backgroundImage: `url('${block.image}')` }"></div>
|
||||||
|
<div class="absolute inset-0 bg-black opacity-80"></div>
|
||||||
|
<div class="absolute p-12 w-full overflow-auto" style="top: 0; bottom: 0;">
|
||||||
|
<div class="flex-row justify-center items-center">
|
||||||
|
<h1 class="text-center text-white font-arctic text-2xl md:text-4xl">{{ block.title || 'Medlemskap' }}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mx-auto max-w-[1280px]">
|
||||||
|
<p v-if="block.showprices" class="mt-2 text-white">
|
||||||
|
Prisen for medlemskap er
|
||||||
|
{{ page.props.pageSettings['membership_fee'] }},- kr per år for voksne eller {{ page.props.pageSettings['membership_child_fee'] }}
|
||||||
|
for barn/ungdom under {{ page.props.pageSettings['membership_child_age_limit'] }} år. Du må være
|
||||||
|
{{ page.props.pageSettings['membership_age_limit'] }} år eller eldre for å bli medlem hos oss. Medlemskapet
|
||||||
|
varer i {{ page.props.pageSettings['membership_time_interval_months'] }} måneder
|
||||||
|
<span v-if="page.props.pageSettings['membership_annual']"> eller ut kalenderåret </span>
|
||||||
|
før det må fornyes. Betalinger kan gjøres på nettsiden via vipps <span v-if="page.props.pageSettings['module_stripe_payment']">eller bankkort</span> ved å besøke
|
||||||
|
<Link :href="route('dashboard')" class="text-amber-400 hover:text-amber-300 underline hover:no-underline">
|
||||||
|
din medlemsside
|
||||||
|
</Link>
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
<p v-if="$page.props.auth.user && block.showprices" class="mt-2 text-white">
|
||||||
|
<span class="font-semibold">Merk:</span> Priser og betingelser kan variere. Besøk medlemssiden for å se
|
||||||
|
dine spesifike betingelser.
|
||||||
|
</p>
|
||||||
|
<div class="mt-2 text-white memberShipBlock" v-html="marked(block.text)">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.memberShipBlock p {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock p:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock a {
|
||||||
|
color: #f59e0b;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock a:hover {
|
||||||
|
color: #d97706;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock a:active {
|
||||||
|
color: #d97706;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock a:focus {
|
||||||
|
color: #d97706;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock a:visited {
|
||||||
|
color: #fcd34d;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock ul {
|
||||||
|
color: #9ca3af;
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
list-style-type: circle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock li p {
|
||||||
|
color: #9ca3af;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock ul li {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock ul li:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock ol {
|
||||||
|
color: #9ca3af;
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
list-style-type: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock ol li {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock ol li:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock hr {
|
||||||
|
border-top-color: #f59e0b;
|
||||||
|
margin-top: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock h1 {
|
||||||
|
@apply font-arctic text-4xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock h2 {
|
||||||
|
color: #f59e0b;
|
||||||
|
font-family: 'Arctic';
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: x-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock h3 {
|
||||||
|
color: #fff;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: large;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock h4 {
|
||||||
|
color: #f59e0b;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: medium;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock h5 {
|
||||||
|
color: #f59e0b;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: small;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock h6 {
|
||||||
|
color: #f59e0b;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: x-small;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock blockquote {
|
||||||
|
color: #9ca3af;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
margin-left: 20px;
|
||||||
|
padding-left: 10px;
|
||||||
|
border-left: 3px solid #ccc;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock code {
|
||||||
|
background-color: #1f2937;
|
||||||
|
color: #ef4444;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
padding: 8px 10px 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-top: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,128 @@
|
|||||||
|
<script setup>
|
||||||
|
import treeview from "vue3-treeview";
|
||||||
|
import "vue3-treeview/dist/style.css";
|
||||||
|
|
||||||
|
import { toRef, watch, reactive, watchEffect, onMounted } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: { type: Object, required: true },
|
||||||
|
images: { type: Array }
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:block']);
|
||||||
|
const local = toRef(props, 'block');
|
||||||
|
|
||||||
|
watch(local, (val) => emit('update:block', val), { deep: true });
|
||||||
|
|
||||||
|
const treeData = reactive({
|
||||||
|
nodes: {},
|
||||||
|
config: {
|
||||||
|
checkboxes: false,
|
||||||
|
dragAndDrop: false,
|
||||||
|
editable: false,
|
||||||
|
roots: []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function buildTreeNodes(images) {
|
||||||
|
const nodes = {};
|
||||||
|
const roots = [];
|
||||||
|
|
||||||
|
images.forEach(item => {
|
||||||
|
const id = `id${item.id}`
|
||||||
|
nodes[id] = {
|
||||||
|
nodeId: item.id,
|
||||||
|
text: item.name,
|
||||||
|
fs_type: item.fs_type,
|
||||||
|
fs_meta: item.fs_meta,
|
||||||
|
children: images.filter(child => child.parent_id === item.id).map(child => `id${child.id}`),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (item.parent_id === null) roots.push(id);
|
||||||
|
})
|
||||||
|
|
||||||
|
return { nodes, roots };
|
||||||
|
}
|
||||||
|
|
||||||
|
const onNodeClick = (node) => {
|
||||||
|
if (node.fs_type === 'file') {
|
||||||
|
local.value.image = extractMetaValue(node, 'symbolic_name');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
const { nodes, roots } = buildTreeNodes(props.images);
|
||||||
|
treeData.nodes = nodes;
|
||||||
|
treeData.config.roots = roots;
|
||||||
|
});
|
||||||
|
|
||||||
|
function extractMetaValue(node, key) {
|
||||||
|
let meta = JSON.parse(node.fs_meta);
|
||||||
|
return meta[key];
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Anker navn (DOM ID)</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.anchorName"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tittel</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.title"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tekst</label>
|
||||||
|
<textarea
|
||||||
|
rows="3"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.text"
|
||||||
|
></textarea>
|
||||||
|
<span class="text-xs">(Dette feltet er markdown kompatibelt)</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="prices-checkbox"
|
||||||
|
aria-describedby="prices-checkbox-text"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="local.showprices"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ms-2 text-sm">
|
||||||
|
<label for="prices-checkbox" class="font-medium text-gray-900 dark:text-gray-300">Vis prissammendrag</label>
|
||||||
|
<p id="prices-checkbox-text" class="text-xs font-normal text-gray-500 dark:text-gray-300">Skru av eller på visningen av prissammendraget nederst i blokken</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Velg bakgrunnsbilde</label>
|
||||||
|
<treeview
|
||||||
|
v-if="images && images.length"
|
||||||
|
@nodeFocus="onNodeClick"
|
||||||
|
:nodes="treeData.nodes"
|
||||||
|
:config="treeData.config"
|
||||||
|
class="mt-4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -0,0 +1,237 @@
|
|||||||
|
<script setup>
|
||||||
|
import { Link, usePage } from '@inertiajs/vue3';
|
||||||
|
import { onMounted, defineProps, computed } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
import { marked } from 'marked';
|
||||||
|
|
||||||
|
const { block, blockData, frontpage } = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
blockData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
frontpage: {
|
||||||
|
type: Boolean
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
const page = usePage();
|
||||||
|
const userRoles = computed(() => page.props.userRoles);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the user has the given role.
|
||||||
|
*
|
||||||
|
* @param string roleName
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
|
||||||
|
const hasRole = (roleName) => userRoles.value.includes(roleName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the number of days until dd.mm.YYYY
|
||||||
|
*
|
||||||
|
* @param string date
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
|
||||||
|
const calculateDaysUntil = (dateStr) => {
|
||||||
|
const [day, month, year] = dateStr.split('.');
|
||||||
|
const targetDate = new Date(year, month - 1, day);
|
||||||
|
|
||||||
|
const today = new Date();
|
||||||
|
today.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
const differenceInMilliseconds = targetDate - today;
|
||||||
|
const differenceInDays = differenceInMilliseconds / (1000 * 60 * 60 * 24);
|
||||||
|
|
||||||
|
return Math.floor(differenceInDays);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section :id="block.anchorName" class="relative block w-full h-screen overflow-hidden">
|
||||||
|
<div class="absolute inset-0 bg-cover" :style="{ backgroundImage: `url('${block.image}')` }"></div>
|
||||||
|
<div class="absolute inset-0 bg-black opacity-80"></div>
|
||||||
|
<div class="absolute p-12 w-full overflow-auto" style="top: 0; bottom: 0;">
|
||||||
|
<div class="flex-row justify-center items-center">
|
||||||
|
<h1 class="text-center text-white font-arctic text-2xl md:text-4xl">{{ block.title || 'Medlemskap' }}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mx-auto max-w-[1280px]">
|
||||||
|
<!-- <img src="/img/medlemmer.jpg" class="border-2 w-[200px] sm:w-[320px] md:w-[640px] lg:w-[800px] border-green-700 rounded-lg float-left mb-1 md:mb-4 mx-2 md:mx-6" alt="ØMS Medlemmer"> -->
|
||||||
|
<p v-if="block.showprices" class="mt-2 text-white">
|
||||||
|
Prisen for medlemskap er
|
||||||
|
{{ page.props.pageSettings['membership_fee'] }},- kr per år for voksne eller {{ page.props.pageSettings['membership_child_fee'] }}
|
||||||
|
for barn/ungdom under {{ page.props.pageSettings['membership_child_age_limit'] }} år. Du må være
|
||||||
|
{{ page.props.pageSettings['membership_age_limit'] }} år eller eldre for å bli medlem. hos oss. Medlemskapet
|
||||||
|
varer i {{ page.props.pageSettings['membership_time_interval_months'] }} måneder
|
||||||
|
<span v-if="page.props.pageSettings['membership_annual']"> eller ut kalenderåret </span>
|
||||||
|
før det må fornyes. Betalinger kan gjøres på nettsiden via vipps <span v-if="page.props.pageSettings['module_stripe_payment']">eller bankkort</span> ved å besøke
|
||||||
|
<Link :href="route('dashboard')" class="text-amber-400 hover:text-amber-300 underline hover:no-underline">
|
||||||
|
din medlemsside
|
||||||
|
</Link>
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
<p v-if="$page.props.auth.user && block.showprices" class="mt-2 text-white">
|
||||||
|
<span class="font-semibold">Merk:</span> Priser og betingelser kan variere. Besøk medlemssiden for å se
|
||||||
|
dine spesifike betingelser.
|
||||||
|
</p>
|
||||||
|
<div class="mt-2 text-white memberShipBlock" v-html="marked(block.text)">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.memberShipBlock p {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock p:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock a {
|
||||||
|
color: #f59e0b;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock a:hover {
|
||||||
|
color: #d97706;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock a:active {
|
||||||
|
color: #d97706;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock a:focus {
|
||||||
|
color: #d97706;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock a:visited {
|
||||||
|
color: #fcd34d;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock ul {
|
||||||
|
color: #9ca3af;
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
list-style-type: circle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock li p {
|
||||||
|
color: #9ca3af;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock ul li {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock ul li:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock ol {
|
||||||
|
color: #9ca3af;
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
list-style-type: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock ol li {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock ol li:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock hr {
|
||||||
|
border-top-color: #f59e0b;
|
||||||
|
margin-top: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock h1 {
|
||||||
|
@apply font-arctic;
|
||||||
|
@apply text-4xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock h2 {
|
||||||
|
color: #f59e0b;
|
||||||
|
font-family: 'Arctic';
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: x-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock h3 {
|
||||||
|
color: #fff;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: large;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock h4 {
|
||||||
|
color: #f59e0b;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: medium;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock h5 {
|
||||||
|
color: #f59e0b;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: small;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock h6 {
|
||||||
|
color: #f59e0b;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: x-small;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock blockquote {
|
||||||
|
color: #9ca3af;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
margin-left: 20px;
|
||||||
|
padding-left: 10px;
|
||||||
|
border-left: 3px solid #ccc;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memberShipBlock code {
|
||||||
|
background-color: #1f2937;
|
||||||
|
color: #ef4444;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
padding: 8px 10px 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-top: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,36 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, ref, toRef, watch } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
const clubName = ref(null);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: { type: Object, required: true }
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:block']);
|
||||||
|
const local = toRef(props, 'block');
|
||||||
|
|
||||||
|
watch(local, (val) => emit('update:block', val), { deep: true });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<header id="frontPageHeader" class="h-[400px] bg-heroBg bg-no-repeat bg-center bg-cover">
|
||||||
|
<div class="h-[400px] bg-heroSoldiers bg-no-repeat bg-bottom z-0">
|
||||||
|
<div class="h-[400px] bg-heroFgR bg-repeat-x bg-bottom z-10">
|
||||||
|
<div class="flex items-end justify-center content-end pt-12">
|
||||||
|
<Link id="logoHeader" :href="route('forsiden')" class="flex justify-center items-center p-2">
|
||||||
|
<img id="clubLogo" src="/img/oms-glow.png" class="w-14 md:w-20 lg:w-28 mr-2 md:mr-6 shadow-2xl" alt="">
|
||||||
|
<p class="text-white text-2xl md:text-4xl lg:text-6xl font-topsecret">
|
||||||
|
<span ref="clubName">{{ block.title || 'Østfold Milsim' }}</span>
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</template>
|
@ -0,0 +1,49 @@
|
|||||||
|
<script setup>
|
||||||
|
import treeview from "vue3-treeview";
|
||||||
|
import "vue3-treeview/dist/style.css";
|
||||||
|
|
||||||
|
import { toRef, watch, reactive, watchEffect } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:block']);
|
||||||
|
|
||||||
|
// Work directly with a reactive reference to the parent block
|
||||||
|
const local = toRef(props, 'block');
|
||||||
|
|
||||||
|
// Optionally: auto-emit updated block on change (if needed elsewhere)
|
||||||
|
watch(local, (val) => {
|
||||||
|
emit('update:block', val);
|
||||||
|
}, { deep: true });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Anker navn (DOM ID)</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.anchorName"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tittel</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.title"
|
||||||
|
@input="update"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,78 @@
|
|||||||
|
<script setup>
|
||||||
|
import { Link } from '@inertiajs/vue3';
|
||||||
|
import { onMounted, ref, defineProps } from 'vue';
|
||||||
|
import { gsap } from 'gsap';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
const { block, blockData, frontpage } = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
blockData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
frontpage: {
|
||||||
|
type: Boolean
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
animateLogo();
|
||||||
|
});
|
||||||
|
|
||||||
|
const clubName = ref(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Club logo animation in the header
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
function animateLogo() {
|
||||||
|
const text = clubName.value.textContent.trim();
|
||||||
|
const chars = Array.from(text);
|
||||||
|
|
||||||
|
// Clear the text content and create a span for each character
|
||||||
|
clubName.value.textContent = '';
|
||||||
|
chars.forEach((char) => {
|
||||||
|
const span = document.createElement('span');
|
||||||
|
span.textContent = char;
|
||||||
|
clubName.value.appendChild(span);
|
||||||
|
});
|
||||||
|
|
||||||
|
const logoTimeline = gsap.timeline({ defaults: { ease: 'power1.out' } });
|
||||||
|
|
||||||
|
// Animate each letter
|
||||||
|
logoTimeline.from(clubName.value.children, {
|
||||||
|
duration: 0.5,
|
||||||
|
opacity: 0,
|
||||||
|
y: 20,
|
||||||
|
stagger: 0.05,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start fading in the logo before the text animation completes
|
||||||
|
logoTimeline.to("#clubLogo", {
|
||||||
|
duration: 1,
|
||||||
|
opacity: 1,
|
||||||
|
}, "-=0.5");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<header :id="block.anchorName" class="h-[400px] bg-heroBg bg-no-repeat bg-center bg-cover">
|
||||||
|
<div class="h-[400px] bg-heroSoldiers bg-no-repeat bg-bottom z-0">
|
||||||
|
<div class="h-[400px] bg-heroFgR bg-repeat-x bg-bottom z-10">
|
||||||
|
<div class="flex items-end justify-center content-end pt-12">
|
||||||
|
<Link id="logoHeader" :href="route('forsiden')" class="flex justify-center items-center p-2">
|
||||||
|
<img id="clubLogo" src="/img/oms-glow.png" class="w-14 md:w-20 lg:w-28 mr-2 md:mr-6 shadow-2xl" alt="">
|
||||||
|
<p class="text-white text-2xl md:text-4xl lg:text-6xl font-topsecret">
|
||||||
|
<span ref="clubName">{{ block.title || 'Østfold Milsim' }}</span>
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</template>
|
77
resources/js/components/Blocks/Statics/FrontPageNewsList.vue
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<script setup>
|
||||||
|
import { defineProps } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const articles = [
|
||||||
|
{
|
||||||
|
headline: 'Taktikker som endret spillet vårt',
|
||||||
|
text: 'I denne grundige analysen utforsker vi de revolusjonerende taktikkene introdusert av treneren som fullstendig forvandlet vårt spill denne sesongen. Fra en defensiv holdning til en offensiv overmakt, dette er historien om hvordan vårt lag gikk fra under...',
|
||||||
|
time: '17/03/2025',
|
||||||
|
category: 'Spillstrategi'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headline: 'Støtte fra tribunen: Våre fantastiske fans',
|
||||||
|
text: 'Et hav av farger og sang fylte stadion, mens tilhengernes lidenskap og energi ga en ekstra "spiller" på banen. Vi dykker ned i hvordan supporterne våre har blitt en uunnværlig del av lagånden og ser på de mest minneverdige øyeblikkene fra tribunen denn...',
|
||||||
|
time: '17/03/2025',
|
||||||
|
category: 'Klubbliv'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headline: 'Hvor er de nå? Oppdateringer fra tidligere ENHET-spillere',
|
||||||
|
text: 'Livet etter å ha forlatt vårt kjære ENHET-lag kan ta mange vendinger. Vi tar et nostalgisk tilbakeblikk og oppdaterer deg på hvor tidligere stjernespillere har endt opp. Bli med på en reise gjennom karrierene deres etter ENHET, fra nye lag til personli...',
|
||||||
|
time: '17/03/2025',
|
||||||
|
category: 'Spillerfokus'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="relative block w-full h-screen overflow-hidden">
|
||||||
|
<div class="absolute inset-0 bg-cover" :style="{ backgroundImage: `url('${block.image}')` }"></div>
|
||||||
|
<div class="absolute inset-0 bg-black opacity-80"></div>
|
||||||
|
<div class="absolute p-12 w-full overflow-auto" style="top: 0; bottom: 0;">
|
||||||
|
<div class="flex-row justify-center items-center">
|
||||||
|
<h1 v-if="block.showtitle" class="text-center text-white font-arctic text-2xl md:text-4xl">{{ block.title || 'Tittel/Overskrift' }}</h1>
|
||||||
|
<h2 v-if="block.showlabel" class="text-center text-amber-600 font-serif text-md md:text-xl">{{ block.label || 'Tittel Merkelapp' }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mx-auto max-w-[1280px]">
|
||||||
|
<div class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 mt-12">
|
||||||
|
<!-- Begin news article loop -->
|
||||||
|
<div
|
||||||
|
v-for="(article, index) in articles"
|
||||||
|
:key="article.id"
|
||||||
|
class="news-article flex justify-normal items-start max-w-md"
|
||||||
|
>
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<img class="h-48 w-32 object-cover border-2 border-amber-800 rounded-lg shadow-md" src="/img/blocks/nyheter_placeholder.jpg" alt="Eksempel bilde">
|
||||||
|
</div>
|
||||||
|
<div class="ml-4">
|
||||||
|
<h3 class="text-sm font-medium text-white font-arctic">
|
||||||
|
<Link href="#" class="hover:underline">
|
||||||
|
{{ article.headline }}
|
||||||
|
</Link>
|
||||||
|
</h3>
|
||||||
|
<span class="mt-1 text-xs text-gray-500">{{ article.time }}</span>
|
||||||
|
<Link href="#" class="ml-4 bg-amber-100 hover:bg-amber-200 text-amber-800 text-xs font-semibold me-2 px-2.5 py-0.5 rounded border border-amber-400 inline-flex items-center justify-center">
|
||||||
|
{{ article.category }}
|
||||||
|
</Link>
|
||||||
|
<p class="mt-1 text-sm text-gray-300">
|
||||||
|
{{ article.text }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- End news article loop -->
|
||||||
|
</div>
|
||||||
|
<div class="mt-12 flex justify-end items-end">
|
||||||
|
<a href="#" class="font-arctic text-amber-600 hover:text-amber-400 no-underline hover:underline">{{ block.buttontext || 'Vis mer' }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
@ -0,0 +1,164 @@
|
|||||||
|
<script setup>
|
||||||
|
import treeview from "vue3-treeview";
|
||||||
|
import "vue3-treeview/dist/style.css";
|
||||||
|
|
||||||
|
import { toRef, watch, reactive, watchEffect, onMounted } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
images: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:block']);
|
||||||
|
const local = toRef(props, 'block');
|
||||||
|
|
||||||
|
watch(local, (val) => emit('update:block', val), { deep: true });
|
||||||
|
|
||||||
|
const treeData = reactive({
|
||||||
|
nodes: {},
|
||||||
|
config: {
|
||||||
|
checkboxes: false,
|
||||||
|
dragAndDrop: false,
|
||||||
|
editable: false,
|
||||||
|
roots: []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function buildTreeNodes(images) {
|
||||||
|
const nodes = {};
|
||||||
|
const roots = [];
|
||||||
|
|
||||||
|
images.forEach(item => {
|
||||||
|
const id = `id${item.id}`
|
||||||
|
nodes[id] = {
|
||||||
|
nodeId: item.id,
|
||||||
|
text: item.name,
|
||||||
|
fs_type: item.fs_type,
|
||||||
|
fs_meta: item.fs_meta,
|
||||||
|
children: images.filter(child => child.parent_id === item.id).map(child => `id${child.id}`),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (item.parent_id === null) roots.push(id);
|
||||||
|
})
|
||||||
|
|
||||||
|
return { nodes, roots };
|
||||||
|
}
|
||||||
|
|
||||||
|
const onNodeClick = (node) => {
|
||||||
|
if (node.fs_type === 'file') {
|
||||||
|
local.value.image = extractMetaValue(node, 'symbolic_name');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
const { nodes, roots } = buildTreeNodes(props.images);
|
||||||
|
treeData.nodes = nodes;
|
||||||
|
treeData.config.roots = roots;
|
||||||
|
});
|
||||||
|
|
||||||
|
function extractMetaValue(node, key) {
|
||||||
|
let meta = JSON.parse(node.fs_meta);
|
||||||
|
return meta[key];
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Anker navn (DOM ID)</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.anchorName"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="title-checkbox"
|
||||||
|
aria-describedby="title-checkbox-text"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="local.showtitle"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ms-2 text-sm">
|
||||||
|
<label for="title-checkbox" class="font-medium text-gray-900 dark:text-gray-300">Vis tittel</label>
|
||||||
|
<p id="title-checkbox-text" class="text-xs font-normal text-gray-500 dark:text-gray-300">Skru tittelen på komponenten av, eller på</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tittel tekst</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.title"
|
||||||
|
:disabled="!local.showtitle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="label-checkbox"
|
||||||
|
aria-describedby="label-checkbox-text"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="local.showlabel"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ms-2 text-sm">
|
||||||
|
<label for="label-checkbox" class="font-medium text-gray-900 dark:text-gray-300">Vis merkelapp</label>
|
||||||
|
<p id="label-checkbox-text" class="text-xs font-normal text-gray-500 dark:text-gray-300">Skru merkelappen øverst på komponenten av, eller på</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Merkelapp tekst</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.label"
|
||||||
|
:disabled="!local.showlabel"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Knapp/Lenke tekst</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.buttontext"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Velg bakgrunnsbilde</label>
|
||||||
|
<treeview
|
||||||
|
v-if="images && images.length"
|
||||||
|
@nodeFocus="onNodeClick"
|
||||||
|
:nodes="treeData.nodes"
|
||||||
|
:config="treeData.config"
|
||||||
|
class="mt-4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,115 @@
|
|||||||
|
<script setup>
|
||||||
|
import { Link } from '@inertiajs/vue3';
|
||||||
|
import { onMounted, computed, defineProps } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
const { block, blockData, frontpage } = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
blockData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
frontpage: {
|
||||||
|
type: Boolean
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve only 3 news articles
|
||||||
|
*/
|
||||||
|
|
||||||
|
const limitedArticles = computed(() => blockData.articles.data.slice(0, 3));
|
||||||
|
|
||||||
|
|
||||||
|
/** Get a node value from json */
|
||||||
|
|
||||||
|
const extractMetaValue = (node, key) => {
|
||||||
|
let meta = JSON.parse(node.fs_meta);
|
||||||
|
|
||||||
|
return meta[key];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* formatDate
|
||||||
|
*
|
||||||
|
* Formats a date string to a Norwegian date format.
|
||||||
|
*
|
||||||
|
* @param {
|
||||||
|
* } dateString
|
||||||
|
*/
|
||||||
|
|
||||||
|
const formatDate = (dateString) => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
const day = ('0' + date.getDate()).slice(-2);
|
||||||
|
const month = ('0' + (date.getMonth() + 1)).slice(-2);
|
||||||
|
const year = date.getFullYear();
|
||||||
|
|
||||||
|
return `${day}/${month}/${year}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dateString
|
||||||
|
*
|
||||||
|
* Formats a date string to a Norwegian time format.
|
||||||
|
* @param {*} dateString
|
||||||
|
*/
|
||||||
|
|
||||||
|
const formatTime = (dateString) => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date.toLocaleTimeString('nb-NO', { hour: '2-digit', minute: '2-digit' });
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section :id="block.anchorName" class="relative block w-full h-screen overflow-hidden">
|
||||||
|
<div class="absolute inset-0 bg-cover" :style="{ backgroundImage: `url('${block.image}')` }"></div>
|
||||||
|
<div class="absolute inset-0 bg-black opacity-80"></div>
|
||||||
|
<div class="absolute p-12 w-full overflow-auto" style="top: 0; bottom: 0;">
|
||||||
|
<div class="flex-row justify-center items-center">
|
||||||
|
<h1 v-if="block.showtitle" class="text-center text-white font-arctic text-2xl md:text-4xl">{{ block.title || 'Tittel/Overskrift' }}</h1>
|
||||||
|
<h2 v-if="block.showlabel" class="text-center text-amber-600 font-serif text-md md:text-xl">{{ block.label || 'Tittel Merkelapp' }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mx-auto max-w-[1280px]">
|
||||||
|
<div class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 mt-12">
|
||||||
|
<!-- Begin news article loop -->
|
||||||
|
<div
|
||||||
|
v-for="(article, index) in blockData.articles.data"
|
||||||
|
:key="article.id"
|
||||||
|
class="news-article flex justify-normal items-start max-w-md"
|
||||||
|
>
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<img v-if="article.image_id" class="h-48 w-32 object-cover border-2 border-amber-800 rounded-lg shadow-md" :src="extractMetaValue(article.image, 'symbolic_name')" :alt="extractMetaValue(article.image, 'title')">
|
||||||
|
</div>
|
||||||
|
<div class="ml-4">
|
||||||
|
<h3 class="text-sm font-medium text-white font-arctic">
|
||||||
|
<Link :href="route('newsArticle', article.slug)" class="hover:underline">
|
||||||
|
{{ article.title }}
|
||||||
|
</Link>
|
||||||
|
</h3>
|
||||||
|
<span class="mt-1 text-xs text-gray-500">{{ formatDate(article.created_at) }}</span>
|
||||||
|
<Link v-if="article.news_category_id" :href="route('newsCategory', article.category.slug)" class="ml-4 bg-amber-100 hover:bg-amber-200 text-amber-800 text-xs font-semibold me-2 px-2.5 py-0.5 rounded border border-amber-400 inline-flex items-center justify-center">
|
||||||
|
{{ article.category.title }}
|
||||||
|
</Link>
|
||||||
|
<p class="mt-1 text-sm text-gray-300">
|
||||||
|
{{ article.excerpt }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- End news article loop -->
|
||||||
|
</div>
|
||||||
|
<div class="mt-12 flex justify-end items-end">
|
||||||
|
<Link :href="route('news')" class="font-arctic text-amber-600 hover:text-amber-400 no-underline hover:underline">{{ block.buttontext || 'Vis mer' }}</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
71
resources/js/components/Blocks/Statics/FrontPageSponsors.vue
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, toRef, watch } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: { type: Object, required: true }
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:block']);
|
||||||
|
const local = toRef(props, 'block');
|
||||||
|
|
||||||
|
watch(local, (val) => emit('update:block', val), { deep: true });
|
||||||
|
|
||||||
|
const sponsors = [
|
||||||
|
{ name: 'Greenleaf Organics A/S', type: 'Sponsor' },
|
||||||
|
{ name: 'Futuretech Robotics AS', type: 'Sponsor' },
|
||||||
|
{ name: 'EcoInnovate Solutions AS', type: 'Sponsor' },
|
||||||
|
{ name: 'Nordic Nest A/S', type: 'Sponsor' },
|
||||||
|
{ name: 'Bright Mind AS', type: 'Sponsor' },
|
||||||
|
{ name: 'Globetrotter Travel Co AS', type: 'Samarbeidspartner' },
|
||||||
|
{ name: 'Aurora Health & Wellness A/S', type: 'Samarbeidspartner' },
|
||||||
|
{ name: 'Artisinal Brews AS', type: 'Samarbeidspartner' }
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="relative block w-full h-screen overflow-hidden">
|
||||||
|
<div class="absolute inset-0 bg-cover" :style="{ backgroundImage: `url('${block.image}')` }"></div>
|
||||||
|
<div class="absolute inset-0 bg-black opacity-80"></div>
|
||||||
|
<div class="absolute p-12 w-full overflow-auto" style="top: 0; bottom: 0;">
|
||||||
|
<div class="flex-row justify-center items-center">
|
||||||
|
<h1 class="text-center text-white font-arctic text-2xl md:text-4xl">{{ block.title || 'Tittel' }}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mx-auto max-w-[1280px]">
|
||||||
|
<div class="col-6 d-flex flex-column sponsor-container">
|
||||||
|
|
||||||
|
<p v-if="block.showtext" class="text-gray-200 mt-6">
|
||||||
|
{{ block.text || 'Intro tekst' }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 p-4 font-arctic text-xl md:text-2xl">
|
||||||
|
<!-- Sponsoroppføring -->
|
||||||
|
<template v-for="(sponsor, index) in sponsors" :key="index">
|
||||||
|
<a v-if="sponsor.type == 'Sponsor'" href="#" class="anchor sponsor-label text-gray-500 hover:text-gray-400 no-underline hover:underline">
|
||||||
|
<span>{{ sponsor.name }}</span>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p v-if="block.showpartnertext" class="text-gray-200 mt-2">
|
||||||
|
{{ block.partnertext || 'Partner intro tekst' }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 p-4 font-arctic text-xl md:text-2xl">
|
||||||
|
<!-- Partneroppføring -->
|
||||||
|
<template v-for="(partner, index) in sponsors" :key="index" href="#">
|
||||||
|
<a v-if="partner.type == 'Samarbeidspartner'" class="anchor sponsor-label text-gray-500 hover:text-gray-400 no-underline hover:underline">
|
||||||
|
<span>{{ partner.name }}</span>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
@ -0,0 +1,164 @@
|
|||||||
|
<script setup>
|
||||||
|
import treeview from "vue3-treeview";
|
||||||
|
import "vue3-treeview/dist/style.css";
|
||||||
|
|
||||||
|
import { toRef, watch, reactive, watchEffect, onMounted } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
images: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:block']);
|
||||||
|
const local = toRef(props, 'block');
|
||||||
|
|
||||||
|
watch(local, (val) => emit('update:block', val), { deep: true });
|
||||||
|
|
||||||
|
const treeData = reactive({
|
||||||
|
nodes: {},
|
||||||
|
config: {
|
||||||
|
checkboxes: false,
|
||||||
|
dragAndDrop: false,
|
||||||
|
editable: false,
|
||||||
|
roots: []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function buildTreeNodes(images) {
|
||||||
|
const nodes = {};
|
||||||
|
const roots = [];
|
||||||
|
|
||||||
|
images.forEach(item => {
|
||||||
|
const id = `id${item.id}`
|
||||||
|
nodes[id] = {
|
||||||
|
nodeId: item.id,
|
||||||
|
text: item.name,
|
||||||
|
fs_type: item.fs_type,
|
||||||
|
fs_meta: item.fs_meta,
|
||||||
|
children: images.filter(child => child.parent_id === item.id).map(child => `id${child.id}`),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (item.parent_id === null) roots.push(id);
|
||||||
|
})
|
||||||
|
|
||||||
|
return { nodes, roots };
|
||||||
|
}
|
||||||
|
|
||||||
|
const onNodeClick = (node) => {
|
||||||
|
if (node.fs_type === 'file') {
|
||||||
|
local.value.image = extractMetaValue(node, 'symbolic_name');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
const { nodes, roots } = buildTreeNodes(props.images);
|
||||||
|
treeData.nodes = nodes;
|
||||||
|
treeData.config.roots = roots;
|
||||||
|
});
|
||||||
|
|
||||||
|
function extractMetaValue(node, key) {
|
||||||
|
let meta = JSON.parse(node.fs_meta);
|
||||||
|
return meta[key];
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Anker navn (DOM ID)</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.anchorName"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tittel tekst</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.title"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="title-checkbox"
|
||||||
|
aria-describedby="title-checkbox-text"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="local.showtext"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ms-2 text-sm">
|
||||||
|
<label for="title-checkbox" class="font-medium text-gray-900 dark:text-gray-300">Vis tekst</label>
|
||||||
|
<p id="title-checkbox-text" class="text-xs font-normal text-gray-500 dark:text-gray-300">Skru introteksten i komponenten av, eller på</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Tekst</label>
|
||||||
|
<textarea
|
||||||
|
rows="3"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.text"
|
||||||
|
:disabled="!local.showtext"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="title-checkbox"
|
||||||
|
aria-describedby="title-checkbox-text"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="local.showpartnertext"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ms-2 text-sm">
|
||||||
|
<label for="title-checkbox" class="font-medium text-gray-900 dark:text-gray-300">Vis partner tekst</label>
|
||||||
|
<p id="title-checkbox-text" class="text-xs font-normal text-gray-500 dark:text-gray-300">Skru partnerteksten i komponenten av, eller på</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Partnertekst</label>
|
||||||
|
<textarea
|
||||||
|
rows="3"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.partnertext"
|
||||||
|
:disabled="!local.showpartnertext"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Velg bakgrunnsbilde</label>
|
||||||
|
<treeview
|
||||||
|
v-if="images && images.length"
|
||||||
|
@nodeFocus="onNodeClick"
|
||||||
|
:nodes="treeData.nodes"
|
||||||
|
:config="treeData.config"
|
||||||
|
class="mt-4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,62 @@
|
|||||||
|
<script setup>
|
||||||
|
import { Link } from '@inertiajs/vue3';
|
||||||
|
import { onMounted, defineProps } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
const { block, blockData, frontpage } = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
blockData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
frontpage: {
|
||||||
|
type: Boolean
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section :id="block.anchorName" class="relative block w-full h-screen overflow-hidden">
|
||||||
|
<div class="absolute inset-0 bg-cover" :style="{ backgroundImage: `url('${block.image}')` }"></div>
|
||||||
|
<div class="absolute inset-0 bg-black opacity-80"></div>
|
||||||
|
<div class="absolute p-12 w-full overflow-auto" style="top: 0; bottom: 0;">
|
||||||
|
<div class="flex-row justify-center items-center">
|
||||||
|
<h1 class="text-center text-white font-arctic text-2xl md:text-4xl">{{ block.title || 'Tittel' }}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mx-auto max-w-[1280px]">
|
||||||
|
<div class="col-6 d-flex flex-column sponsor-container">
|
||||||
|
|
||||||
|
<p v-if="block.showtext" class="text-gray-200">
|
||||||
|
{{ block.text || 'Intro tekst' }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 p-4 font-arctic text-xl md:text-2xl">
|
||||||
|
<!-- Sponsoroppføring -->
|
||||||
|
<Link v-for="(sponsor, index) in blockData.sponsors" :key="sponsor.id" :href="route('sponsor', sponsor.slug)" class="anchor sponsor-label text-gray-500 hover:text-gray-400 no-underline hover:underline">
|
||||||
|
{{ sponsor.name }}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p v-if="blockData.partners && blockData.partners.length && block.showpartnertext" class="text-gray-200 mt-2">
|
||||||
|
{{ block.partnertext || 'Partner intro tekst' }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 p-4 font-arctic text-xl md:text-2xl">
|
||||||
|
<!-- Sponsoroppføring -->
|
||||||
|
<Link v-for="(partner, index) in blockData.partners" :key="partner.id" :href="route('sponsor', partner.slug)" class="anchor sponsor-label text-gray-500 hover:text-gray-400 no-underline hover:underline">
|
||||||
|
{{ partner.name }}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
23
resources/js/components/Blocks/Statics/PageFooter.vue
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
import { usePage } from '@inertiajs/vue3';
|
||||||
|
|
||||||
|
import ArcticLogo from '@/Components/FrontPage/ArcticSoftwareFrontpageLogo.vue';
|
||||||
|
import FooterLinks from '@/Components/FrontPage/FooterSection.vue';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
const page = usePage();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<footer class="w-full bg-white border-t-2 border-green-700">
|
||||||
|
<FooterLinks :pageSettings="page.props.pageSettings"></FooterLinks>
|
||||||
|
<div class="p-4 flex items-center justify-center">
|
||||||
|
<ArcticLogo></ArcticLogo>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</template>
|
@ -0,0 +1,23 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
import { usePage } from '@inertiajs/vue3';
|
||||||
|
|
||||||
|
import ArcticLogo from '@/Components/FrontPage/ArcticSoftwareFrontpageLogo.vue';
|
||||||
|
import FooterLinks from '@/Components/FrontPage/FooterSection.vue';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
const page = usePage();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<footer class="w-full bg-white border-t-2 border-green-700">
|
||||||
|
<FooterLinks :pageSettings="page.props.pageSettings"></FooterLinks>
|
||||||
|
<div class="p-4 flex items-center justify-center">
|
||||||
|
<ArcticLogo></ArcticLogo>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</template>
|
89
resources/js/components/Blocks/Text/TwoColumnText.vue
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, defineProps } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const firstColumn = props.block.firstcolumn || [
|
||||||
|
{ text: 'Vårt samhold styrkes gjennom regelmessige arrangementer, med månedlige lokale turneringer og kvartalsvise vennskapsspill mot naboklubber.', style: 'heading' },
|
||||||
|
{ text: 'Hvert år arrangerer ENHET også en spennende utenlandstur hvor våre lag får utfordre internasjonale motstandere og oppleve nye kulturer. Bli med og opplev spenningen ved å representere ENHET både hjemme og på turer.', style: 'heading' },
|
||||||
|
{ text: 'Fotball er mer enn et spill; det er en verdensomspennende lidenskap som lærer oss verdien av lagarbeid og fair play. Som den mest populære sporten i verden, bringer fotball sammen mennesker fra alle livets hjørner, og bygger broer på tvers av kulturelle og språklige barrierer.', style: 'regular' },
|
||||||
|
{ text: 'Denne vakre sporten er en fest for fysisk dyktighet og strategisk tenkning, hvor spenningen på banen kun er matchet av fansens entusiasme. Fra spennende lokale kamper til den elektriske atmosfæren ved verdensmesterskapet, fotball tilbyr en unik kilde til glede og fellesskapsfølelse', style: 'regular' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const secondColumn = props.block.secondcolumn || [
|
||||||
|
{ text: 'Bli med på våre ukentlige treninger, strategiseminarer og veldedighetsaktiviteter som styrker både kropp og fellesskap.', style: 'headingbold' },
|
||||||
|
{ text: 'Og trenger du utstyr har vi har et bredt spekter av fotballrelatert utstyr tilgjengelig for våre medlemmer, for å sikre at alle har det de trenger for å spille sitt beste.', style: 'regular' },
|
||||||
|
{ text: 'Hvordan begynne? Å starte med fotball har aldri vært enklere. Kom til en åpen trening eller kontakt oss for en prat om hvordan du kan bli en del av ENHET. Alt du trenger for å starte er et par fotballsko og et ønske om å lære. Vi tar oss av resten – fra drakter til treningsutstyr.', style: 'regular' }
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="mx-auto max-w-[1280px] bg-black">
|
||||||
|
<div class="grid gap-8 grid-cols-1 md:grid-cols-2 p-6">
|
||||||
|
<div class="max-w-2xl text-gray-200">
|
||||||
|
<template v-for="(paragraph, index) in firstColumn" :index="index">
|
||||||
|
<h1 v-if="paragraph.style === 'headinglarge'" class="text-gray-500 text-2xl md:text-4xl font-arctic">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</h1>
|
||||||
|
<h2 v-if="paragraph.style === 'headingbold'" class="text-gray-500 text-xl md:text-2xl font-arctic mt-4">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</h2>
|
||||||
|
<h3 v-else-if="paragraph.style === 'heading'" class="text-amber-600 text-xl md:text-2xl font-serif mt-1">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</h3>
|
||||||
|
<p v-else-if="paragraph.style === 'regular'" class="mt-2">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</p>
|
||||||
|
<iframe
|
||||||
|
v-else-if="paragraph.style === 'video'"
|
||||||
|
class="mt-6 w-72 h-72 md:w-96 md:h-96 lg:w-[560px] lg:h-[315px]"
|
||||||
|
:src="paragraph.text"
|
||||||
|
title="YouTube video spiller"
|
||||||
|
frameborder="0"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||||
|
allowfullscreen
|
||||||
|
>
|
||||||
|
|
||||||
|
</iframe>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="max-w-2xl text-gray-200">
|
||||||
|
<template v-for="(paragraph, index) in secondColumn" :index="index">
|
||||||
|
<h1 v-if="paragraph.style === 'headinglarge'" class="text-gray-500 text-2xl md:text-4xl font-arctic">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</h1>
|
||||||
|
<h2 v-if="paragraph.style === 'headingbold'" class="text-gray-500 text-xl md:text-2xl font-arctic mt-4">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</h2>
|
||||||
|
<h3 v-else-if="paragraph.style === 'heading'" class="text-amber-600 text-xl md:text-2xl font-serif mt-1">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</h3>
|
||||||
|
<p v-else-if="paragraph.style === 'regular'" class="mt-2">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</p>
|
||||||
|
<iframe
|
||||||
|
v-else-if="paragraph.style === 'video'"
|
||||||
|
class="mt-6 w-72 h-72 md:w-96 md:h-96 lg:w-[560px] lg:h-[315px]"
|
||||||
|
:src="paragraph.text"
|
||||||
|
title="YouTube video spiller"
|
||||||
|
frameborder="0"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||||
|
allowfullscreen
|
||||||
|
>
|
||||||
|
|
||||||
|
</iframe>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
213
resources/js/components/Blocks/Text/TwoColumnTextOptions.vue
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
<script setup>
|
||||||
|
import Icon from '@/Components/Icon.vue';
|
||||||
|
import { toRef, ref, onMounted } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:block']);
|
||||||
|
const local = toRef(props, 'block');
|
||||||
|
|
||||||
|
// Drag state first column
|
||||||
|
const firstDraggedIndex = ref(null);
|
||||||
|
|
||||||
|
function handleDragStartPFirst(event, index) {
|
||||||
|
firstDraggedIndex.value = index;
|
||||||
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
event.dataTransfer.setData('text/plain', index);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDragOverPFirst(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDropPFirst(event, index) {
|
||||||
|
event.preventDefault();
|
||||||
|
const fromIndex = firstDraggedIndex.value;
|
||||||
|
if (fromIndex === null || fromIndex === index) return;
|
||||||
|
|
||||||
|
const item = local.value.firstcolumn.splice(fromIndex, 1)[0];
|
||||||
|
local.value.firstcolumn.splice(index, 0, item);
|
||||||
|
firstDraggedIndex.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
function addPFirst() {
|
||||||
|
local.value.firstcolumn.push({
|
||||||
|
text: '',
|
||||||
|
style: 'regular',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removePFirst(index) {
|
||||||
|
local.value.firstcolumn.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Drag state second column
|
||||||
|
const secondDraggedIndex = ref(null);
|
||||||
|
|
||||||
|
function handleDragStartPSecond(event, index) {
|
||||||
|
secondDraggedIndex.value = index;
|
||||||
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
event.dataTransfer.setData('text/plain', index);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDragOverPSecond(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDropPSecond(event, index) {
|
||||||
|
event.preventDefault();
|
||||||
|
const fromIndex = secondDraggedIndex.value;
|
||||||
|
if (fromIndex === null || fromIndex === index) return;
|
||||||
|
|
||||||
|
const item = local.value.secondcolumn.splice(fromIndex, 1)[0];
|
||||||
|
local.value.secondcolumn.splice(index, 0, item);
|
||||||
|
secondDraggedIndex.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
function addPSecond() {
|
||||||
|
local.value.secondcolumn.push({
|
||||||
|
text: '',
|
||||||
|
style: 'regular',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removePSecond(index) {
|
||||||
|
local.value.secondcolumn.splice(index, 1);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="mb-2">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Anker navn (DOM ID)</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
|
||||||
|
v-model="local.anchorName"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<h3 class="font-bold text-sm text-gray-800 dark:text-white">
|
||||||
|
Venstre kolonne
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div
|
||||||
|
v-for="(paragraph, index) in local.firstcolumn"
|
||||||
|
:key="index"
|
||||||
|
class="flex items-start gap-2 p-4 rounded border dark:border-gray-600 bg-gray-50 dark:bg-gray-800"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="handleDragStartPFirst($event, index)"
|
||||||
|
@dragover="handleDragOverPFirst"
|
||||||
|
@drop="handleDropPFirst($event, index)"
|
||||||
|
>
|
||||||
|
<div class="cursor-move mt-1 text-gray-500 dark:text-gray-400">
|
||||||
|
<Icon name="move" class="w-4 h-4" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 space-y-2">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-sm font-semibold text-gray-700 dark:text-gray-300">Paragraf {{ index + 1 }}</span>
|
||||||
|
<button @click="removePFirst(index)" class="text-red-500 hover:underline text-xs">Fjern</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<label :for="`style-l-${index}`" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Velg en tekststil</label>
|
||||||
|
<select
|
||||||
|
:id="`style-l-${index}`"
|
||||||
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||||
|
v-model="paragraph.style"
|
||||||
|
>
|
||||||
|
<option value="headinglarge">Stor overskrift</option>
|
||||||
|
<option value="heading">Overskrift</option>
|
||||||
|
<option value="headingbold">Fet overskrift</option>
|
||||||
|
<option value="regular">Vanlig</option>
|
||||||
|
<option value="video">Video</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400">Tekst/Innhold</label>
|
||||||
|
<textarea rows="2" class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white" v-model="paragraph.text"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button @click="addPFirst" class="mt-2 px-4 py-2 bg-blue-600 text-white text-sm rounded hover:bg-blue-700">
|
||||||
|
Legg til ny paragraf
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<h3 class="font-bold text-sm text-gray-800 dark:text-white">
|
||||||
|
Høyre kolonne
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div
|
||||||
|
v-for="(paragraph, index) in local.secondcolumn"
|
||||||
|
:key="index"
|
||||||
|
class="flex items-start gap-2 p-4 rounded border dark:border-gray-600 bg-gray-50 dark:bg-gray-800"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="handleDragStartPSecond($event, index)"
|
||||||
|
@dragover="handleDragOverPSecond"
|
||||||
|
@drop="handleDropPSecond($event, index)"
|
||||||
|
>
|
||||||
|
<div class="cursor-move mt-1 text-gray-500 dark:text-gray-400">
|
||||||
|
<Icon name="move" class="w-4 h-4" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 space-y-2">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-sm font-semibold text-gray-700 dark:text-gray-300">Paragraf {{ index + 1 }}</span>
|
||||||
|
<button @click="removePSecond(index)" class="text-red-500 hover:underline text-xs">Fjern</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-2">
|
||||||
|
<label :for="`style-r-${index}`" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Velg en tekststil</label>
|
||||||
|
<select
|
||||||
|
:id="`style-r-${index}`"
|
||||||
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||||
|
v-model="paragraph.style"
|
||||||
|
>
|
||||||
|
<option value="headinglarge">Stor overskrift</option>
|
||||||
|
<option value="heading">Overskrift</option>
|
||||||
|
<option value="headingbold">Fet overskrift</option>
|
||||||
|
<option value="regular">Vanlig</option>
|
||||||
|
<option value="video">Video</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-medium text-gray-600 dark:text-gray-400">Tekst/Innhold</label>
|
||||||
|
<textarea rows="2" class="mt-1 block w-full rounded-md border-gray-300 dark:border-gray-600 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:text-white" v-model="paragraph.text"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button @click="addPSecond" class="mt-2 px-4 py-2 bg-blue-600 text-white text-sm rounded hover:bg-blue-700">
|
||||||
|
Legg til ny paragraf
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,89 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, defineProps } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
block: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const firstColumn = props.block.firstcolumn || [
|
||||||
|
{ text: 'Vårt samhold styrkes gjennom regelmessige arrangementer, med månedlige lokale turneringer og kvartalsvise vennskapsspill mot naboklubber.', style: 'heading' },
|
||||||
|
{ text: 'Hvert år arrangerer ENHET også en spennende utenlandstur hvor våre lag får utfordre internasjonale motstandere og oppleve nye kulturer. Bli med og opplev spenningen ved å representere ENHET både hjemme og på turer.', style: 'heading' },
|
||||||
|
{ text: 'Fotball er mer enn et spill; det er en verdensomspennende lidenskap som lærer oss verdien av lagarbeid og fair play. Som den mest populære sporten i verden, bringer fotball sammen mennesker fra alle livets hjørner, og bygger broer på tvers av kulturelle og språklige barrierer.', style: 'regular' },
|
||||||
|
{ text: 'Denne vakre sporten er en fest for fysisk dyktighet og strategisk tenkning, hvor spenningen på banen kun er matchet av fansens entusiasme. Fra spennende lokale kamper til den elektriske atmosfæren ved verdensmesterskapet, fotball tilbyr en unik kilde til glede og fellesskapsfølelse', style: 'regular' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const secondColumn = props.block.secondcolumn || [
|
||||||
|
{ text: 'Bli med på våre ukentlige treninger, strategiseminarer og veldedighetsaktiviteter som styrker både kropp og fellesskap.', style: 'headingbold' },
|
||||||
|
{ text: 'Og trenger du utstyr har vi har et bredt spekter av fotballrelatert utstyr tilgjengelig for våre medlemmer, for å sikre at alle har det de trenger for å spille sitt beste.', style: 'regular' },
|
||||||
|
{ text: 'Hvordan begynne? Å starte med fotball har aldri vært enklere. Kom til en åpen trening eller kontakt oss for en prat om hvordan du kan bli en del av ENHET. Alt du trenger for å starte er et par fotballsko og et ønske om å lære. Vi tar oss av resten – fra drakter til treningsutstyr.', style: 'regular' }
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section :id="block.anchorName" class="mx-auto max-w-[1280px] bg-black">
|
||||||
|
<div class="grid gap-8 grid-cols-1 md:grid-cols-2 p-6">
|
||||||
|
<div class="max-w-2xl text-gray-200">
|
||||||
|
<template v-for="(paragraph, index) in firstColumn" :index="index">
|
||||||
|
<h1 v-if="paragraph.style === 'headinglarge'" class="text-gray-500 text-2xl md:text-4xl font-arctic">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</h1>
|
||||||
|
<h2 v-if="paragraph.style === 'headingbold'" class="text-gray-500 text-xl md:text-2xl font-arctic mt-4">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</h2>
|
||||||
|
<h3 v-else-if="paragraph.style === 'heading'" class="text-amber-600 text-xl md:text-2xl font-serif mt-1">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</h3>
|
||||||
|
<p v-else-if="paragraph.style === 'regular'" class="mt-2">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</p>
|
||||||
|
<iframe
|
||||||
|
v-else-if="paragraph.style === 'video'"
|
||||||
|
class="mt-6 w-72 h-72 md:w-96 md:h-96 lg:w-[560px] lg:h-[315px]"
|
||||||
|
:src="paragraph.text"
|
||||||
|
title="YouTube video spiller"
|
||||||
|
frameborder="0"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||||
|
allowfullscreen
|
||||||
|
>
|
||||||
|
|
||||||
|
</iframe>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="max-w-2xl text-gray-200">
|
||||||
|
<template v-for="(paragraph, index) in secondColumn" :index="index">
|
||||||
|
<h1 v-if="paragraph.style === 'headinglarge'" class="text-gray-500 text-2xl md:text-4xl font-arctic">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</h1>
|
||||||
|
<h2 v-if="paragraph.style === 'headingbold'" class="text-gray-500 text-xl md:text-2xl font-arctic mt-4">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</h2>
|
||||||
|
<h3 v-else-if="paragraph.style === 'heading'" class="text-amber-600 text-xl md:text-2xl font-serif mt-1">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</h3>
|
||||||
|
<p v-else-if="paragraph.style === 'regular'" class="mt-2">
|
||||||
|
{{ paragraph.text || '' }}
|
||||||
|
</p>
|
||||||
|
<iframe
|
||||||
|
v-else-if="paragraph.style === 'video'"
|
||||||
|
class="mt-6 w-72 h-72 md:w-96 md:h-96 lg:w-[560px] lg:h-[315px]"
|
||||||
|
:src="paragraph.text"
|
||||||
|
title="YouTube video spiller"
|
||||||
|
frameborder="0"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||||
|
allowfullscreen
|
||||||
|
>
|
||||||
|
|
||||||
|
</iframe>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
3
resources/js/components/ClubLogo.vue
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
<img src="/img/oms.png" alt="ØMS Logo">
|
||||||
|
</template>
|
7
resources/js/components/DangerButton.vue
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<template>
|
||||||
|
<button
|
||||||
|
class="inline-flex items-center px-4 py-2 bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 transition ease-in-out duration-150"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</button>
|
||||||
|
</template>
|
22
resources/js/components/EventBus.vue
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<script>
|
||||||
|
// This bus handles generic events from components
|
||||||
|
import { reactive, watchEffect } from 'vue';
|
||||||
|
|
||||||
|
export const state = reactive({
|
||||||
|
event: null,
|
||||||
|
payload: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
export function emit(eventName, payload) {
|
||||||
|
state.event = eventName;
|
||||||
|
state.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function on(eventName, callback) {
|
||||||
|
watchEffect(() => {
|
||||||
|
if (state.event === eventName) {
|
||||||
|
callback(state.payload);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,17 @@
|
|||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
<div class="w-24">
|
||||||
|
<img src="/img/as-logo-us.png" alt="Arctic Software logo">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="ml-2">
|
||||||
|
<h2 class="text-2xl text-sky-400 font-arctic">Polar<span class="text-sky-700">Press</span></h2>
|
||||||
|
<h4 class="text-sm">Design & Produksjon</h4>
|
||||||
|
<span class="text-xs text-right">av <a target="_new" href="https://arcticsoftware.no" class="text-primary-800 underline font-semibold hover:text-primary-500 hover:no-underline hover:font-normal">Arctic Software AS</a></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
177
resources/js/components/FrontPage/FooterSection.vue
Normal file
14
resources/js/components/InputLabel.vue
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<label class="block font-medium text-sm text-gray-700">
|
||||||
|
<span v-if="value">{{ value }}</span>
|
||||||
|
<span v-else><slot /></span>
|
||||||
|
</label>
|
||||||
|
</template>
|
105
resources/js/components/Modal.vue
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed, onMounted, onUnmounted, watch } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
maxWidth: {
|
||||||
|
type: String,
|
||||||
|
default: '2xl',
|
||||||
|
},
|
||||||
|
closeable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
lightTheme: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['close']);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.show,
|
||||||
|
() => {
|
||||||
|
if (props.show) {
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
} else {
|
||||||
|
document.body.style.overflow = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
if (props.closeable) {
|
||||||
|
emit('close');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeOnEscape = (e) => {
|
||||||
|
if (e.key === 'Escape' && props.show) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => document.addEventListener('keydown', closeOnEscape));
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
document.removeEventListener('keydown', closeOnEscape);
|
||||||
|
document.body.style.overflow = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
const maxWidthClass = computed(() => {
|
||||||
|
return {
|
||||||
|
sm: 'sm:max-w-sm',
|
||||||
|
md: 'sm:max-w-md',
|
||||||
|
lg: 'sm:max-w-lg',
|
||||||
|
xl: 'sm:max-w-xl',
|
||||||
|
'2xl': 'sm:max-w-2xl',
|
||||||
|
}[props.maxWidth];
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Teleport to="body">
|
||||||
|
<Transition leave-active-class="duration-200">
|
||||||
|
<div v-show="show" class="fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 z-50" scroll-region>
|
||||||
|
<Transition
|
||||||
|
enter-active-class="ease-out duration-300"
|
||||||
|
enter-from-class="opacity-0"
|
||||||
|
enter-to-class="opacity-100"
|
||||||
|
leave-active-class="ease-in duration-200"
|
||||||
|
leave-from-class="opacity-100"
|
||||||
|
leave-to-class="opacity-0"
|
||||||
|
>
|
||||||
|
<div v-show="show" class="fixed inset-0 transform transition-all" @click="close">
|
||||||
|
<div class="absolute inset-0 bg-gray-500 opacity-75" />
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
<Transition
|
||||||
|
enter-active-class="ease-out duration-300"
|
||||||
|
enter-from-class="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
|
enter-to-class="opacity-100 translate-y-0 sm:scale-100"
|
||||||
|
leave-active-class="ease-in duration-200"
|
||||||
|
leave-from-class="opacity-100 translate-y-0 sm:scale-100"
|
||||||
|
leave-to-class="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-show="show"
|
||||||
|
class="mb-6 rounded-lg shadow-xl transform transition-all sm:w-full sm:mx-auto"
|
||||||
|
:class="{
|
||||||
|
'bg-white': lightTheme,
|
||||||
|
'bg-gray-700': !lightTheme,
|
||||||
|
}, maxWidthClass"
|
||||||
|
>
|
||||||
|
<slot v-if="show" />
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
16
resources/js/components/PageBuilderLogo.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
<div class="w-16">
|
||||||
|
<img src="/img/as-logo-us.png" alt="Arctic Software PolarPress logo">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="ml-2">
|
||||||
|
<h2 class="text-2xl text-sky-400 font-arctic">Polar<span class="text-sky-700">Press</span></h2>
|
||||||
|
<h4 class="text-sm">Sidebygger</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
7
resources/js/components/PrimaryButton.vue
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<template>
|
||||||
|
<button
|
||||||
|
class="inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 focus:bg-gray-700 active:bg-gray-900 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 transition ease-in-out duration-150"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</button>
|
||||||
|
</template>
|
17
resources/js/components/SecondaryButton.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'button',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<button
|
||||||
|
:type="type"
|
||||||
|
class="inline-flex items-center px-4 py-2 bg-white border border-gray-300 rounded-md font-semibold text-xs text-gray-700 uppercase tracking-widest shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 disabled:opacity-25 transition ease-in-out duration-150"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</button>
|
||||||
|
</template>
|
31
resources/js/components/TextInput.vue
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
defineEmits(['update:modelValue']);
|
||||||
|
|
||||||
|
const input = ref(null);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (input.value.hasAttribute('autofocus')) {
|
||||||
|
input.value.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({ focus: () => input.value.focus() });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<input
|
||||||
|
class="border-gray-300 focus:border-green-500 focus:ring-green-500 rounded-md shadow-sm"
|
||||||
|
:value="modelValue"
|
||||||
|
@input="$emit('update:modelValue', $event.target.value)"
|
||||||
|
ref="input"
|
||||||
|
/>
|
||||||
|
</template>
|
138
resources/js/components/Toast.vue
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, watch, computed } from 'vue';
|
||||||
|
import { usePage } from '@inertiajs/vue3';
|
||||||
|
import { toastMessage } from '@/Composables/useToast';
|
||||||
|
|
||||||
|
const show = ref(false);
|
||||||
|
const message = ref('');
|
||||||
|
const type = ref('success');
|
||||||
|
const page = usePage();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
duration: {
|
||||||
|
type: Number,
|
||||||
|
default: 4,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const closeToast = () => {
|
||||||
|
show.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(() => page.props.flash, (flash) => {
|
||||||
|
if (flash.success || flash.error || flash.warning || flash.info) {
|
||||||
|
show.value = true;
|
||||||
|
message.value = flash.success || flash.error || flash.warning || flash.info;
|
||||||
|
type.value = flash.success
|
||||||
|
? 'success'
|
||||||
|
: flash.error
|
||||||
|
? 'danger'
|
||||||
|
: flash.warning
|
||||||
|
? 'warning'
|
||||||
|
: 'info';
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
show.value = false;
|
||||||
|
}, props.duration * 1000);
|
||||||
|
}
|
||||||
|
}, { immediate: true });
|
||||||
|
|
||||||
|
// Watch for global toast messages
|
||||||
|
watch(toastMessage, (val) => {
|
||||||
|
if (val) {
|
||||||
|
message.value = val.message;
|
||||||
|
type.value = val.type;
|
||||||
|
show.value = true;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
show.value = false;
|
||||||
|
toastMessage.value = null;
|
||||||
|
}, props.duration * 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const toastClasses = computed(() => {
|
||||||
|
console.log('Toast type is:', type.value);
|
||||||
|
switch (type.value) {
|
||||||
|
case 'success':
|
||||||
|
return 'text-green-500 bg-green-100 dark:bg-green-800 dark:text-green-200';
|
||||||
|
case 'danger':
|
||||||
|
return 'text-red-500 bg-red-100 dark:bg-red-800 dark:text-red-200';
|
||||||
|
case 'warning':
|
||||||
|
return 'text-orange-500 bg-orange-100 dark:bg-orange-700 dark:text-orange-200';
|
||||||
|
case 'info':
|
||||||
|
return 'text-blue-500 bg-blue-100 dark:bg-blue-800 dark:text-blue-200';
|
||||||
|
default:
|
||||||
|
return 'text-gray-800 bg-white dark:bg-gray-800 dark:text-gray-200';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<transition name="fade">
|
||||||
|
<div
|
||||||
|
v-if="show"
|
||||||
|
class="fixed top-5 right-5 z-50 w-full max-w-xs flex items-center p-4 rounded-lg shadow-sm"
|
||||||
|
:class="toastClasses"
|
||||||
|
role="alert"
|
||||||
|
>
|
||||||
|
<div class="inline-flex items-center justify-center shrink-0 w-8 h-8 rounded-lg">
|
||||||
|
<svg
|
||||||
|
v-if="type === 'success'"
|
||||||
|
class="w-5 h-5"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 8.207-4 4a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L9 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414Z"/>
|
||||||
|
</svg>
|
||||||
|
<svg
|
||||||
|
v-else-if="type === 'danger'"
|
||||||
|
class="w-5 h-5"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 11.793a1 1 0 1 1-1.414 1.414L10 11.414l-2.293 2.293a1 1 0 0 1-1.414-1.414L8.586 10 6.293 7.707a1 1 0 0 1 1.414-1.414L10 8.586l2.293-2.293a1 1 0 0 1 1.414 1.414L11.414 10l2.293 2.293Z"/>
|
||||||
|
</svg>
|
||||||
|
<svg
|
||||||
|
v-else-if="type === 'warning'"
|
||||||
|
class="w-5 h-5"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM10 15a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm1-4a1 1 0 0 1-2 0V6a1 1 0 0 1 2 0v5Z"/>
|
||||||
|
</svg>
|
||||||
|
<svg
|
||||||
|
v-else
|
||||||
|
class="w-5 h-5"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path d="M10 2a8 8 0 100 16 8 8 0 000-16zm1 11H9v-2h2v2zm0-4H9V5h2v4z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="ms-3 text-sm font-normal">
|
||||||
|
{{ message }}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="closeToast"
|
||||||
|
class="ms-auto -mx-1.5 -my-1.5 text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex items-center justify-center h-8 w-8 dark:hover:text-white dark:hover:bg-gray-700"
|
||||||
|
>
|
||||||
|
<svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1l6 6m0 0l6 6M7 7L1 13m6-6l6-6"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.4s ease;
|
||||||
|
}
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
14
resources/js/composables/useToast.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
export const toastMessage = ref(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {'success' | 'info' | 'danger' | 'warning'} type
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
export function showToast(type, message) {
|
||||||
|
toastMessage.value = {
|
||||||
|
type: String(type),
|
||||||
|
message: String(message),
|
||||||
|
};
|
||||||
|
}
|
35
resources/js/layouts/AuthenticatedLayout.vue
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Link } from '@inertiajs/vue3';
|
||||||
|
import AuthLayout from '@/layouts/auth/AuthSimpleLayout.vue';
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full p-8 bg-gray-900">
|
||||||
|
<ul class="flex justify-end gap-3 text-sm leading-normal">
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
:href="route('forsiden')"
|
||||||
|
target="_blank"
|
||||||
|
class="inline-block mr-4 rounded-sm border border-black bg-[#1b1b18] px-5 py-1.5 text-sm leading-normal text-white hover:border-black hover:bg-black dark:border-[#eeeeec] dark:bg-[#eeeeec] dark:text-[#1C1C1A] dark:hover:border-white dark:hover:bg-white"
|
||||||
|
>
|
||||||
|
⬅️ Tilbake
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
:href="route('page-builder.landing-page.create')"
|
||||||
|
target="_blank"
|
||||||
|
class="inline-block rounded-sm border border-black bg-[#1b1b18] px-5 py-1.5 text-sm leading-normal text-white hover:border-black hover:bg-black dark:border-[#eeeeec] dark:bg-[#eeeeec] dark:text-[#1C1C1A] dark:hover:border-white dark:hover:bg-white"
|
||||||
|
>
|
||||||
|
🧾 Ny side
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<AuthLayout :title="title" :description="description">
|
||||||
|
<slot />
|
||||||
|
</AuthLayout>
|
||||||
|
</template>
|
47
resources/js/layouts/PageBuilderLayout.vue
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, useSlots, computed } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
import Toast from '@/Components/Toast.vue';
|
||||||
|
|
||||||
|
const slots = useSlots();
|
||||||
|
const hasHeader = computed(() => !!slots.header)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
|
||||||
|
// Force light mode (dark mode not implemented, yet)
|
||||||
|
// if the user has selected darkmode in the dashboard
|
||||||
|
document.documentElement.classList.remove('dark');
|
||||||
|
localStorage.setItem('dark', 'false');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Toast :duration="8" />
|
||||||
|
<!-- Warn for small screens -->
|
||||||
|
<div class="lg:hidden text-center p-6 bg-yellow-100 text-yellow-800">
|
||||||
|
Denne funksjonen er kun tilgjengelig på større skjermer (LG og opp).
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main layout for large screens -->
|
||||||
|
<div class="hidden lg:block min-h-screen">
|
||||||
|
<!-- Optional Sticky Header -->
|
||||||
|
<header
|
||||||
|
v-if="slots.header"
|
||||||
|
class="fixed top-0 left-0 w-full z-30 bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700 px-6 py-2 shadow-sm"
|
||||||
|
>
|
||||||
|
<div class="max-w-screen-xl mx-auto flex justify-between items-center h-[48px]">
|
||||||
|
<slot name="header" />
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main :class="{ 'pt-[56px]': hasHeader }">
|
||||||
|
<slot />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Add any layout-specific styling here */
|
||||||
|
</style>
|
@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import AppLogoIcon from '@/components/AppLogoIcon.vue';
|
import AppLogoIcon from '@/components/AppLogoIcon.vue';
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import PageLogo from '@/Components/ArcticFooterLogo.vue';
|
||||||
import { Link } from '@inertiajs/vue3';
|
import { Link } from '@inertiajs/vue3';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
@ -12,9 +13,9 @@ defineProps<{
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex min-h-svh flex-col items-center justify-center gap-6 bg-muted p-6 md:p-10">
|
<div class="flex min-h-svh flex-col items-center justify-center gap-6 bg-muted p-6 md:p-10">
|
||||||
<div class="flex w-full max-w-md flex-col gap-6">
|
<div class="flex w-full max-w-md flex-col gap-6">
|
||||||
<Link :href="route('home')" class="flex items-center gap-2 self-center font-medium">
|
<Link :href="route('forsiden')" class="flex items-center gap-2 self-center font-medium">
|
||||||
<div class="flex h-9 w-9 items-center justify-center">
|
<div class="flex h-9 w-9 items-center justify-center">
|
||||||
<AppLogoIcon class="size-9 fill-current text-black dark:text-white" />
|
<PageLogo />
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import AppLogoIcon from '@/components/AppLogoIcon.vue';
|
import AppLogoIcon from '@/components/AppLogoIcon.vue';
|
||||||
import { Link } from '@inertiajs/vue3';
|
import { Link } from '@inertiajs/vue3';
|
||||||
|
import PageLogo from '@/Components/ArcticFooterLogo.vue';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
title?: string;
|
title?: string;
|
||||||
@ -13,18 +14,19 @@ defineProps<{
|
|||||||
<div class="w-full max-w-sm">
|
<div class="w-full max-w-sm">
|
||||||
<div class="flex flex-col gap-8">
|
<div class="flex flex-col gap-8">
|
||||||
<div class="flex flex-col items-center gap-4">
|
<div class="flex flex-col items-center gap-4">
|
||||||
<Link :href="route('home')" class="flex flex-col items-center gap-2 font-medium">
|
|
||||||
<div class="mb-1 flex h-9 w-9 items-center justify-center rounded-md">
|
|
||||||
<AppLogoIcon class="size-9 fill-current text-[var(--foreground)] dark:text-white" />
|
|
||||||
</div>
|
|
||||||
<span class="sr-only">{{ title }}</span>
|
|
||||||
</Link>
|
|
||||||
<div class="space-y-2 text-center">
|
<div class="space-y-2 text-center">
|
||||||
<h1 class="text-xl font-medium">{{ title }}</h1>
|
<h1 class="text-xl font-medium">{{ title }}</h1>
|
||||||
<p class="text-center text-sm text-muted-foreground">{{ description }}</p>
|
<p class="text-center text-sm text-muted-foreground">{{ description }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<slot />
|
<slot />
|
||||||
|
|
||||||
|
<Link :href="route('forsiden')" class="flex flex-col items-center gap-2 font-medium my-8">
|
||||||
|
<div class="flex h-9 w-9 items-center justify-center rounded-md">
|
||||||
|
<PageLogo />
|
||||||
|
</div>
|
||||||
|
<span class="sr-only">{{ title }}</span>
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,7 +16,7 @@ defineProps<{
|
|||||||
<div class="relative grid h-dvh flex-col items-center justify-center px-8 sm:px-0 lg:max-w-none lg:grid-cols-2 lg:px-0">
|
<div class="relative grid h-dvh flex-col items-center justify-center px-8 sm:px-0 lg:max-w-none lg:grid-cols-2 lg:px-0">
|
||||||
<div class="relative hidden h-full flex-col bg-muted p-10 text-white dark:border-r lg:flex">
|
<div class="relative hidden h-full flex-col bg-muted p-10 text-white dark:border-r lg:flex">
|
||||||
<div class="absolute inset-0 bg-zinc-900" />
|
<div class="absolute inset-0 bg-zinc-900" />
|
||||||
<Link :href="route('home')" class="relative z-20 flex items-center text-lg font-medium">
|
<Link :href="route('forsiden')" class="relative z-20 flex items-center text-lg font-medium">
|
||||||
<AppLogoIcon class="mr-2 size-8 fill-current text-white" />
|
<AppLogoIcon class="mr-2 size-8 fill-current text-white" />
|
||||||
{{ name }}
|
{{ name }}
|
||||||
</Link>
|
</Link>
|
||||||
|
250
resources/js/pages/Backend/PageBuilder/Create.vue
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
<script setup>
|
||||||
|
import { Head, Link, usePage, useForm } from '@inertiajs/vue3';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
import blocks from '@/Utils/blocks';
|
||||||
|
import PageBuilderLayout from '@/layouts/PageBuilderLayout.vue';
|
||||||
|
import BlockGroup from '@/Components/Blocks/BlockGroup.vue';
|
||||||
|
import BlockWrapper from '@/Components/Blocks/BlockWrapper.vue';
|
||||||
|
import AppLogo from '@/Components/PageBuilderLogo.vue';
|
||||||
|
import InputError from '@/Components/InputError.vue';
|
||||||
|
|
||||||
|
const groups = blocks.groups;
|
||||||
|
const draft = ref([]);
|
||||||
|
const page = usePage();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
const { builtPages, images } = defineProps({
|
||||||
|
builtPages: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
|
||||||
|
images: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ([]),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const cloneBlock = (block) => {
|
||||||
|
block.uuid = uuidv4();
|
||||||
|
return block;
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteBlock = (index) => {
|
||||||
|
draft.value.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDrop(event) {
|
||||||
|
const data = event.dataTransfer.getData('application/json');
|
||||||
|
if (data) {
|
||||||
|
try {
|
||||||
|
const block = JSON.parse(data);
|
||||||
|
block.uuid = uuidv4();
|
||||||
|
draft.value.push(block);
|
||||||
|
console.log('📦 Dropped block:', block);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to parse dropped block", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Drag and drop
|
||||||
|
|
||||||
|
const draggingIndex = ref(null)
|
||||||
|
|
||||||
|
function handleDragStart(event, index) {
|
||||||
|
draggingIndex.value = index;
|
||||||
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
event.dataTransfer.setData('text/plain', index);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDragOver(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDropReorder(event, dropIndex) {
|
||||||
|
event.preventDefault();
|
||||||
|
const fromIndex = draggingIndex.value;
|
||||||
|
if (fromIndex === null || fromIndex === dropIndex) return;
|
||||||
|
|
||||||
|
const block = draft.value.splice(fromIndex, 1)[0];
|
||||||
|
draft.value.splice(dropIndex, 0, block);
|
||||||
|
draggingIndex.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Save form
|
||||||
|
const pageForm = useForm({
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
publish: false,
|
||||||
|
mainpage: false,
|
||||||
|
linked: false,
|
||||||
|
linkorder: 0,
|
||||||
|
visibility: 'public'
|
||||||
|
});
|
||||||
|
|
||||||
|
const savePage = () => {
|
||||||
|
const dropdown = document.getElementById('dropdownInformation');
|
||||||
|
if (dropdown) dropdown.classList.add('hidden');
|
||||||
|
|
||||||
|
pageForm.content = JSON.stringify(draft.value);
|
||||||
|
pageForm.post(route('page-builder.landing-page.store'), {
|
||||||
|
preserveScroll: true,
|
||||||
|
onSuccess: () => {
|
||||||
|
// onSuccess, the user is redirected to the index page for the time being, so toast handling has to be implemented there
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
console.warn("Valideringsfeil ved lagring.")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Head title="Ny Side" />
|
||||||
|
|
||||||
|
<PageBuilderLayout>
|
||||||
|
<template #header>
|
||||||
|
<AppLogo />
|
||||||
|
<h3 class="text-lg font-semibold">Ny side</h3>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<button id="dropdownInformationButton" data-dropdown-toggle="dropdownInformation" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center inline-flex items-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" type="button">
|
||||||
|
Handlinger
|
||||||
|
<svg class="w-2.5 h-2.5 ms-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Dropdown menu -->
|
||||||
|
<div id="dropdownInformation" class="z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow-sm w-44 dark:bg-gray-700 dark:divide-gray-600">
|
||||||
|
<div class="px-4 py-3 text-sm text-gray-900 dark:text-white">
|
||||||
|
<div>{{ page.props.auth.user.name }}</div>
|
||||||
|
<div class="font-medium truncate">{{ page.props.auth.user.email }}</div>
|
||||||
|
</div>
|
||||||
|
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200" aria-labelledby="dropdownInformationButton">
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
@click.prevent="savePage"
|
||||||
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white"
|
||||||
|
>
|
||||||
|
Lagre side
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="py-2">
|
||||||
|
<Link :href="route('page-builder.index')" class="block px-4 py-2 btn btn-sm btn-ghost hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
|
||||||
|
Lukk
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="flex h-screen overflow-hidden">
|
||||||
|
<!-- Sidebar with form & block groups -->
|
||||||
|
<div class="bg-slate-100 overflow-y-auto w-1/6 p-4 space-y-4">
|
||||||
|
<div class="space-y-4 p-4 rounded border dark:border-gray-600 bg-gray-50 dark:bg-gray-800">
|
||||||
|
<div class="mb-4">
|
||||||
|
<label
|
||||||
|
for="page_title-text"
|
||||||
|
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
|
||||||
|
>
|
||||||
|
Sidetittel
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="page_title-text"
|
||||||
|
aria-describedby="page_title-text-explanation"
|
||||||
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
||||||
|
placeholder="Skriv inn en tittel"
|
||||||
|
v-model="pageForm.title"
|
||||||
|
>
|
||||||
|
<InputError :message="pageForm.errors.title" class="mt-2" />
|
||||||
|
<p id="page_title-text-explanation" class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
Tittelen på siden vil være synlig i fanearket i nettleseren hos besøkende, samt brukes til å generere URL (slug)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="inline-flex items-center cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="pageForm.linked" class="sr-only peer">
|
||||||
|
<div class="relative w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600 dark:peer-checked:bg-blue-600"></div>
|
||||||
|
<span class="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300">Menylenke</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="steps-range" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Menylenke rekkefølge</label>
|
||||||
|
<input id="steps-range" :disabled="!pageForm.linked" v-model="pageForm.linkorder" type="range" min="0" max="20" step="1" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700">
|
||||||
|
<span class="text-xs">Prioritet: {{ pageForm.linkorder }} (høyere verdi kommer først)</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="inline-flex items-center cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="pageForm.publish" class="sr-only peer">
|
||||||
|
<div class="relative w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600 dark:peer-checked:bg-blue-600"></div>
|
||||||
|
<span class="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300">Publisert</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="inline-flex items-center cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="pageForm.mainpage" class="sr-only peer">
|
||||||
|
<div class="relative w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600 dark:peer-checked:bg-blue-600"></div>
|
||||||
|
<span class="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300">Sett som hovedside</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<input :checked="pageForm.visibility === 'public'" id="page_state-radio-1" v-model="pageForm.visibility" type="radio" value="public" name="page_state-radio" class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
||||||
|
<label for="page_state-radio-1" class="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300">Synlig for alle</label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<input :checked="pageForm.visibility === 'private'" id="page_state-radio-2" v-model="pageForm.visibility" type="radio" value="private" name="page_state-radio" class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
||||||
|
<label for="page_state-radio-2" class="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300">Bare synlig for medlemmer</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<BlockGroup
|
||||||
|
v-for="group in groups"
|
||||||
|
:key="group.uuid"
|
||||||
|
:title="group.title"
|
||||||
|
:blocks="group.blocks"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Builder canvas -->
|
||||||
|
<div
|
||||||
|
class="bg-white dark:bg-gray-800 w-5/6 p-6 overflow-y-auto"
|
||||||
|
@dragover.prevent
|
||||||
|
@drop="handleDrop"
|
||||||
|
>
|
||||||
|
<div v-if="draft.length === 0" class="text-gray-500 text-sm italic">
|
||||||
|
Dra inn blokker fra venstre for å begynne.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-for="(block, index) in draft"
|
||||||
|
:key="block.uuid"
|
||||||
|
class="mb-4"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="handleDragStart($event, index)"
|
||||||
|
@dragover="handleDragOver"
|
||||||
|
@drop="handleDropReorder($event, index)"
|
||||||
|
>
|
||||||
|
<BlockWrapper :images="images" :block="block" @delete="() => deleteBlock(index)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PageBuilderLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* scoped styles for the create screen */
|
||||||
|
</style>
|
623
resources/js/pages/Backend/PageBuilder/Edit.vue
Normal file
@ -0,0 +1,623 @@
|
|||||||
|
<script setup>
|
||||||
|
import { Head, Link, usePage, useForm, router } from '@inertiajs/vue3';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import { ref, onMounted, watch, nextTick } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
import { showToast } from '@/Composables/useToast.js';
|
||||||
|
|
||||||
|
import blocks from '@/Utils/blocks';
|
||||||
|
import PageBuilderLayout from '@/layouts/PageBuilderLayout.vue';
|
||||||
|
import BlockGroup from '@/Components/Blocks/BlockGroup.vue';
|
||||||
|
import BlockWrapper from '@/Components/Blocks/BlockWrapper.vue';
|
||||||
|
import AppLogo from '@/Components/PageBuilderLogo.vue';
|
||||||
|
import InputError from '@/Components/InputError.vue';
|
||||||
|
import Modal from '@/Components/Modal.vue';
|
||||||
|
import InputLabel from '@/Components/InputLabel.vue';
|
||||||
|
import PrimaryButton from '@/Components/PrimaryButton.vue';
|
||||||
|
import SecondaryButton from '@/Components/SecondaryButton.vue';
|
||||||
|
import DangerButton from '@/Components/DangerButton.vue';
|
||||||
|
import TextInput from '@/Components/TextInput.vue';
|
||||||
|
|
||||||
|
let initialContent = revision.content;
|
||||||
|
if (typeof initialContent === 'string') {
|
||||||
|
try {
|
||||||
|
initialContent = JSON.parse(initialContent);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Failed to parse revision.content:', e);
|
||||||
|
initialContent = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const groups = blocks.groups;
|
||||||
|
const draft = ref(initialContent);
|
||||||
|
const isDirty = ref(false);
|
||||||
|
const isDrawerOpen = ref(false);
|
||||||
|
const page = usePage();
|
||||||
|
const autoSaveFunction = ref(true);
|
||||||
|
|
||||||
|
const autosaveInterval = 30000;
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
|
||||||
|
// Init auto save
|
||||||
|
setInterval(() => {
|
||||||
|
if (isDirty.value && !isDrawerOpen.value) {
|
||||||
|
autoSaveRevision();
|
||||||
|
}
|
||||||
|
}, autosaveInterval);
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
revision,
|
||||||
|
images,
|
||||||
|
revisions
|
||||||
|
} = defineProps({
|
||||||
|
revision: { type: Object, required: true },
|
||||||
|
images: { type: Array, default: () => ([]) },
|
||||||
|
revisions: { type: Object, required: true }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Auto-save function
|
||||||
|
|
||||||
|
const autoSaveRevision = () => {
|
||||||
|
if (autoSaveFunction.value) {
|
||||||
|
isDirty.value = false;
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
revision_uuid: revision.uuid,
|
||||||
|
title: pageForm.title,
|
||||||
|
content: JSON.stringify(draft.value),
|
||||||
|
publish: pageForm.publish,
|
||||||
|
mainpage: pageForm.mainpage,
|
||||||
|
linked: pageForm.linked,
|
||||||
|
linkorder: pageForm.linkorder,
|
||||||
|
visibility: pageForm.visibility,
|
||||||
|
autosave: true
|
||||||
|
};
|
||||||
|
|
||||||
|
router.patch(route('page-builder.landing-page.patch'), payload, {
|
||||||
|
preserveScroll: true,
|
||||||
|
preserveState: false,
|
||||||
|
onSuccess: () => {
|
||||||
|
showToast('info', 'Endringer lagret automatisk.');
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
showToast('danger', 'Automatisk lagring misslykkes ...');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const cloneBlock = (block) => {
|
||||||
|
block.uuid = uuidv4();
|
||||||
|
return block;
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteBlock = (index) => {
|
||||||
|
draft.value.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDrop(event) {
|
||||||
|
const data = event.dataTransfer.getData('application/json');
|
||||||
|
if (data) {
|
||||||
|
try {
|
||||||
|
const block = JSON.parse(data);
|
||||||
|
block.uuid = uuidv4();
|
||||||
|
draft.value.push(block);
|
||||||
|
console.log('📦 Dropped block:', block);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to parse dropped block", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Drag and drop
|
||||||
|
|
||||||
|
const draggingIndex = ref(null)
|
||||||
|
|
||||||
|
function handleDragStart(event, index) {
|
||||||
|
draggingIndex.value = index;
|
||||||
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
event.dataTransfer.setData('text/plain', index);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDragOver(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleDropReorder(event, dropIndex) {
|
||||||
|
event.preventDefault();
|
||||||
|
const fromIndex = draggingIndex.value;
|
||||||
|
if (fromIndex === null || fromIndex === dropIndex) return;
|
||||||
|
|
||||||
|
const block = draft.value.splice(fromIndex, 1)[0];
|
||||||
|
draft.value.splice(dropIndex, 0, block);
|
||||||
|
draggingIndex.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Save form
|
||||||
|
const pageForm = useForm({
|
||||||
|
revision_uuid: revision.uuid,
|
||||||
|
title: revision.title || '',
|
||||||
|
content: '',
|
||||||
|
publish: revision.page.is_published,
|
||||||
|
mainpage: revision.page.main,
|
||||||
|
linked: revision.page.linked,
|
||||||
|
linkorder: revision.page.linkorder,
|
||||||
|
visibility: revision.page.visibility || 'public'
|
||||||
|
});
|
||||||
|
|
||||||
|
const savePage = () => {
|
||||||
|
isDirty.value = false;
|
||||||
|
const dropdown = document.getElementById('dropdownInformation');
|
||||||
|
if (dropdown) dropdown.classList.add('hidden');
|
||||||
|
|
||||||
|
pageForm.content = JSON.stringify(draft.value);
|
||||||
|
pageForm.patch(route('page-builder.landing-page.patch'), {
|
||||||
|
preserveScroll: true,
|
||||||
|
onSuccess: () => {
|
||||||
|
// onSuccess, the user is redirected to the index page for the time being, so toast handling has to be implemented there
|
||||||
|
// Edit: Toast handling is now handled in the PageBuilder layout through it's own component
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
console.warn("Valideringsfeil ved lagring.")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* formatDate
|
||||||
|
*
|
||||||
|
* Formats a date string to a Norwegian date format.
|
||||||
|
*
|
||||||
|
* @param {
|
||||||
|
* } dateString
|
||||||
|
*/
|
||||||
|
|
||||||
|
const formatDate = (dateString) => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
const day = ('0' + date.getDate()).slice(-2);
|
||||||
|
const month = ('0' + (date.getMonth() + 1)).slice(-2);
|
||||||
|
const year = date.getFullYear();
|
||||||
|
|
||||||
|
return `${day}/${month}/${year}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dateString
|
||||||
|
*
|
||||||
|
* Formats a date string to a Norwegian time format.
|
||||||
|
* @param {*} dateString
|
||||||
|
*/
|
||||||
|
|
||||||
|
const formatTime = (dateString) => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date.toLocaleTimeString('nb-NO', { hour: '2-digit', minute: '2-digit' });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Watch the document for any changes to prevent autosaving if no changes are made
|
||||||
|
watch([draft, pageForm], () => {
|
||||||
|
if (autoSaveFunction.value) {
|
||||||
|
isDirty.value = true;
|
||||||
|
}
|
||||||
|
}, { deep: true });
|
||||||
|
|
||||||
|
// Save as routines and modal handling
|
||||||
|
|
||||||
|
const saveAsModal = ref(false);
|
||||||
|
const saveAsTitle = ref(null);
|
||||||
|
|
||||||
|
const saveAsForm = useForm({
|
||||||
|
page_id: revision.page.id,
|
||||||
|
title: revision.title || '',
|
||||||
|
content: '',
|
||||||
|
publish: revision.page.is_published,
|
||||||
|
mainpage: revision.page.main,
|
||||||
|
linked: revision.page.linked,
|
||||||
|
linkorder: revision.page.linkorder,
|
||||||
|
visibility: revision.page.visibility || 'public'
|
||||||
|
});
|
||||||
|
|
||||||
|
const opensaveAsModal = () => {
|
||||||
|
const dropdown = document.getElementById('dropdownInformation');
|
||||||
|
if (dropdown) dropdown.classList.add('hidden');
|
||||||
|
saveAsModal.value = true;
|
||||||
|
isDrawerOpen.value = true; // Don't autosave while modal is open
|
||||||
|
|
||||||
|
nextTick(() => { // Make sure page is rendered, code inside the tick selects the text in the input field.
|
||||||
|
if (saveAsTitle.value) {
|
||||||
|
const inputElement = saveAsTitle.value.$el;
|
||||||
|
inputElement.focus();
|
||||||
|
inputElement.select();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const closesaveAsModal = () => {
|
||||||
|
saveAsForm.reset();
|
||||||
|
saveAsModal.value = false;
|
||||||
|
isDrawerOpen.value = false; // Re-enable auto save
|
||||||
|
};
|
||||||
|
|
||||||
|
const revisionSaveAs = () => {
|
||||||
|
const dropdown = document.getElementById('dropdownInformation');
|
||||||
|
if (dropdown) dropdown.classList.add('hidden');
|
||||||
|
|
||||||
|
saveAsForm.content = JSON.stringify(draft.value);
|
||||||
|
saveAsForm.post(route('page-builder.landing-page.save-as'), {
|
||||||
|
preserveScroll: false,
|
||||||
|
onSuccess: () => closesaveAsModal(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open revision routines and modal handling
|
||||||
|
|
||||||
|
const openModal = ref(false);
|
||||||
|
const rowClicked = ref(false);
|
||||||
|
|
||||||
|
const openForm = useForm({
|
||||||
|
revision_uuid: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const showOpenModal = () => {
|
||||||
|
const dropdown = document.getElementById('dropdownInformation');
|
||||||
|
if (dropdown) dropdown.classList.add('hidden');
|
||||||
|
|
||||||
|
openModal.value = true;
|
||||||
|
isDrawerOpen.value = true; // Don't autosave while modal is open
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeOpenModal = () => {
|
||||||
|
openModal.value = false;
|
||||||
|
isDrawerOpen.value = false; // Re-enable auto save
|
||||||
|
|
||||||
|
openForm.reset();
|
||||||
|
rowClicked.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectRevision = (uuid, index) => {
|
||||||
|
openForm.revision_uuid = uuid;
|
||||||
|
|
||||||
|
if (uuid != revision.uuid) { // Prevent opening of current revision
|
||||||
|
rowClicked.value = index;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const openRevision = () => {
|
||||||
|
router.get(route('page-builder.builder.edit', openForm.revision_uuid));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set active routines
|
||||||
|
|
||||||
|
const setActiveForm = useForm({
|
||||||
|
revision_uuid: revision.uuid,
|
||||||
|
title: revision.title || '',
|
||||||
|
content: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const setActive = () => {
|
||||||
|
const dropdown = document.getElementById('dropdownInformation');
|
||||||
|
if (dropdown) dropdown.classList.add('hidden');
|
||||||
|
|
||||||
|
setActiveForm.content = JSON.stringify(draft.value);
|
||||||
|
setActiveForm.put(route('page-builder.landing-page.set-active'));
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal :show="openModal" @close="closeOpenModal()" max-width="4xl">
|
||||||
|
<div class="p-6 bg-white dark:bg-gray-800 rounded-md">
|
||||||
|
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-400">
|
||||||
|
Tilgjengelige revisjoner
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p class="mt-1 text-sm text-gray-600 dark:text-gray-200">
|
||||||
|
Velg en versjon av denne siden du ønsker å åpne
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="mt-2 relative overflow-x-auto">
|
||||||
|
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
|
||||||
|
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-6 py-3">
|
||||||
|
Tittel
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="px-6 py-3">
|
||||||
|
Forfatter
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="px-6 py-3">
|
||||||
|
Versjon
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="px-6 py-3">
|
||||||
|
Oppdatert
|
||||||
|
</th>
|
||||||
|
<th scope="col" class="px-6 py-3">
|
||||||
|
Opprettet
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="(pageRevision, index) in revisions"
|
||||||
|
:key="index"
|
||||||
|
class="dark:border-gray-700 border-gray-200"
|
||||||
|
:class="{
|
||||||
|
'bg-gray-100 dark:bg-gray-600': rowClicked == index + 1,
|
||||||
|
'bg-white dark:bg-gray-800': !rowClicked,
|
||||||
|
'cursor-pointer': pageRevision.uuid != revision.uuid
|
||||||
|
}"
|
||||||
|
@click="selectRevision(pageRevision.uuid, index + 1)"
|
||||||
|
>
|
||||||
|
<th scope="row" class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||||
|
<div class="flex gap-2 justify-normal items-center">
|
||||||
|
<span>
|
||||||
|
{{ pageRevision.title }}
|
||||||
|
</span>
|
||||||
|
<span v-show="pageRevision.active" class="w-4 h-4 text-yellow-600 dark: dark:text-yellow-400">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
{{ pageRevision.author.name }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
{{ pageRevision.version }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
{{ formatDate(pageRevision.updated_at) }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
{{ formatDate(pageRevision.created_at) }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-6 flex justify-end">
|
||||||
|
<SecondaryButton @click="closeOpenModal()"> Avbryt </SecondaryButton>
|
||||||
|
|
||||||
|
<PrimaryButton
|
||||||
|
class="ml-3"
|
||||||
|
:class="{ 'opacity-25': openForm.processing }"
|
||||||
|
:disabled="openForm.processing"
|
||||||
|
v-show="rowClicked"
|
||||||
|
@click="openRevision"
|
||||||
|
>
|
||||||
|
Åpne
|
||||||
|
</PrimaryButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Modal :show="saveAsModal" @close="closesaveAsModal()">
|
||||||
|
<div class="p-6 bg-white dark:bg-gray-800 rounded-md">
|
||||||
|
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-400">
|
||||||
|
Lagre som ny revisjon
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p class="mt-1 text-sm text-gray-600 dark:text-gray-200">
|
||||||
|
Dette vil opprette en ny versjon og kopi av siden
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="mt-6">
|
||||||
|
<InputLabel for="titleSaveAs" value="Ny tittel" class="text-black dark:text-gray-400" />
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
id="titleSaveAs"
|
||||||
|
ref="saveAsTitle"
|
||||||
|
type="text"
|
||||||
|
class="mt-1 block w-full dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white"
|
||||||
|
placeholder="Oppgi ny tittel"
|
||||||
|
v-model="saveAsForm.title"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<InputError :message="saveAsForm.errors.title" class="mt-2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-6 flex justify-end">
|
||||||
|
<SecondaryButton @click="closesaveAsModal()"> Avbryt </SecondaryButton>
|
||||||
|
|
||||||
|
<PrimaryButton
|
||||||
|
class="ml-3"
|
||||||
|
:class="{ 'opacity-25': saveAsForm.processing }"
|
||||||
|
:disabled="saveAsForm.processing"
|
||||||
|
@click="revisionSaveAs"
|
||||||
|
>
|
||||||
|
Lagre som
|
||||||
|
</PrimaryButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Head title="Rediger Side" />
|
||||||
|
|
||||||
|
<PageBuilderLayout>
|
||||||
|
<template #header>
|
||||||
|
<AppLogo />
|
||||||
|
<h3 class="text-lg font-semibold">Rediger "{{ revision.title }}"</h3>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<button id="dropdownInformationButton" data-dropdown-toggle="dropdownInformation" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center inline-flex items-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800" type="button">
|
||||||
|
Handlinger
|
||||||
|
<svg class="w-2.5 h-2.5 ms-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Dropdown menu -->
|
||||||
|
<div id="dropdownInformation" class="z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow-sm w-44 dark:bg-gray-700 dark:divide-gray-600">
|
||||||
|
<div class="px-4 py-3 text-sm text-gray-900 dark:text-white">
|
||||||
|
<div>{{ page.props.auth.user.name }}</div>
|
||||||
|
<div class="font-medium truncate">{{ page.props.auth.user.email }}</div>
|
||||||
|
</div>
|
||||||
|
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200" aria-labelledby="dropdownInformationButton">
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
@click="showOpenModal"
|
||||||
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white"
|
||||||
|
>
|
||||||
|
Åpne
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
@click.prevent="savePage"
|
||||||
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white"
|
||||||
|
>
|
||||||
|
Lagre
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
@click="opensaveAsModal"
|
||||||
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white"
|
||||||
|
>
|
||||||
|
Lagre som
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
:href="route('page-builder.landing-page.preview', revision.uuid)"
|
||||||
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white"
|
||||||
|
>
|
||||||
|
Forhåndsvis
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div v-if="!revision.active" class="py-2">
|
||||||
|
<a href="#" @click.prevent="setActive" class="block px-4 py-2 btn btn-sm btn-ghost hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
|
||||||
|
Sett aktiv
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="py-2">
|
||||||
|
<Link :href="route('page-builder.index')" class="block px-4 py-2 btn btn-sm btn-ghost hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
|
||||||
|
Lukk
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="flex h-screen overflow-hidden">
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<div class="bg-slate-100 overflow-y-auto w-1/6 p-4 space-y-4">
|
||||||
|
<div class="space-y-4 pt-4 pb-2 pl-4 pr-4 rounded border dark:border-gray-600 bg-gray-50 dark:bg-gray-800">
|
||||||
|
<div>
|
||||||
|
<label class="inline-flex items-center cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="autoSaveFunction" class="sr-only peer">
|
||||||
|
<div class="relative w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600 dark:peer-checked:bg-blue-600"></div>
|
||||||
|
<span class="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300">
|
||||||
|
Autolagring <span v-if="autoSaveFunction">På</span><span v-else>Av</span>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="revision.active" class="space-y-4 p-4 rounded border dark:border-gray-600 bg-gray-50 dark:bg-gray-800">
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="page_title-text" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
|
||||||
|
Sidetittel
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="page_title-text"
|
||||||
|
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white"
|
||||||
|
placeholder="Skriv inn en tittel"
|
||||||
|
v-model="pageForm.title"
|
||||||
|
>
|
||||||
|
<InputError :message="pageForm.errors.title" class="mt-2" />
|
||||||
|
<p id="page_title-text-explanation" class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
Tittelen på siden vil være synlig i fanearket i nettleseren hos besøkende, samt brukes til å generere URL (slug)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="inline-flex items-center cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="pageForm.linked" class="sr-only peer">
|
||||||
|
<div class="relative w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600 dark:peer-checked:bg-blue-600"></div>
|
||||||
|
<span class="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300">Menylenke</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="steps-range" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Menylenke rekkefølge</label>
|
||||||
|
<input id="steps-range" :disabled="!pageForm.linked" v-model="pageForm.linkorder" type="range" min="0" max="20" step="1" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700">
|
||||||
|
<span class="text-xs">Prioritet: {{ pageForm.linkorder }} (høyere verdi kommer først)</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="inline-flex items-center cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="pageForm.publish" class="sr-only peer">
|
||||||
|
<div class="relative w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600 dark:peer-checked:bg-blue-600"></div>
|
||||||
|
<span class="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300">Publisert</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="inline-flex items-center cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="pageForm.mainpage" class="sr-only peer">
|
||||||
|
<div class="relative w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600 dark:peer-checked:bg-blue-600"></div>
|
||||||
|
<span class="ms-3 text-sm font-medium text-gray-900 dark:text-gray-300">Sett som hovedside</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<input id="page_state-radio-1" v-model="pageForm.visibility" type="radio" value="public" name="page_state-radio"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
||||||
|
<label for="page_state-radio-1" class="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300">Synlig for alle</label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<input id="page_state-radio-2" v-model="pageForm.visibility" type="radio" value="private" name="page_state-radio"
|
||||||
|
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
||||||
|
<label for="page_state-radio-2" class="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300">Bare synlig for medlemmer</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Block groups -->
|
||||||
|
<BlockGroup
|
||||||
|
v-for="group in groups"
|
||||||
|
:key="group.uuid"
|
||||||
|
:title="group.title"
|
||||||
|
:blocks="group.blocks"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Canvas -->
|
||||||
|
<div class="bg-white dark:bg-gray-800 w-5/6 p-6 overflow-y-auto" @dragover.prevent @drop="handleDrop">
|
||||||
|
<div v-if="draft.length === 0" class="text-gray-500 text-sm italic">
|
||||||
|
Dra inn blokker fra venstre for å begynne.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-for="(block, index) in draft"
|
||||||
|
:key="block.uuid"
|
||||||
|
class="mb-4"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="handleDragStart($event, index)"
|
||||||
|
@dragover="handleDragOver"
|
||||||
|
@drop="handleDropReorder($event, index)"
|
||||||
|
>
|
||||||
|
<BlockWrapper
|
||||||
|
:images="images"
|
||||||
|
:block="block"
|
||||||
|
@delete="() => deleteBlock(index)"
|
||||||
|
@drawer-state="isDrawerOpen = $event"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PageBuilderLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* scoped styles for the edit screen */
|
||||||
|
</style>
|
170
resources/js/pages/Backend/PageBuilder/Index.vue
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<script setup>
|
||||||
|
import AuthenticatedLayout from '@/layouts/AuthenticatedLayout.vue';
|
||||||
|
import Modal from '@/Components/Modal.vue';
|
||||||
|
import SecondaryButton from '@/Components/SecondaryButton.vue';
|
||||||
|
import DangerButton from '@/Components/DangerButton.vue';
|
||||||
|
|
||||||
|
import { Head, usePage, useForm, Link, router } from '@inertiajs/vue3';
|
||||||
|
import { computed, onMounted, ref } from 'vue';
|
||||||
|
import { initFlowbite } from 'flowbite';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initFlowbite();
|
||||||
|
});
|
||||||
|
|
||||||
|
const page = usePage();
|
||||||
|
const userRoles = computed(() => page.props.userRoles);
|
||||||
|
const userPermissions = computed(() => page.props.userPermissions);
|
||||||
|
|
||||||
|
const {
|
||||||
|
builtPages,
|
||||||
|
} = defineProps({
|
||||||
|
builtPages: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check user permissions from Laravel
|
||||||
|
|
||||||
|
const hasPermission = (permissionName) => {
|
||||||
|
return userPermissions.value.some(userPermissions => userPermissions.name === permissionName);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get thumbnail picture from the content property
|
||||||
|
|
||||||
|
const getThumbs = (lPage) => {
|
||||||
|
try {
|
||||||
|
const blocks = typeof lPage.content === 'string'
|
||||||
|
? JSON.parse(lPage.content)
|
||||||
|
: lPage.content;
|
||||||
|
|
||||||
|
return blocks
|
||||||
|
.filter(block => block.thumbUrl)
|
||||||
|
.map(block => block.thumbUrl);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Invalid JSON in page content:', e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Confirm deletion modal
|
||||||
|
|
||||||
|
const deleteModal = ref(false);
|
||||||
|
|
||||||
|
const deleteForm = useForm({
|
||||||
|
id: null
|
||||||
|
});
|
||||||
|
|
||||||
|
const openDeleteModal = (lPage) => {
|
||||||
|
deleteForm.id = lPage.id;
|
||||||
|
deleteModal.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeDeleteModal = () => {
|
||||||
|
deleteForm.reset();
|
||||||
|
deleteModal.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const deletePage = () => {
|
||||||
|
deleteForm.delete(route('page-builder.landing-page.delete'), {
|
||||||
|
preserveScroll: true,
|
||||||
|
onSuccess: () => closeDeleteModal(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal :show="deleteModal" @close="closeDeleteModal()">
|
||||||
|
<div class="p-6 bg-white dark:bg-gray-800 rounded-md">
|
||||||
|
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-400">
|
||||||
|
Bekreft sletting av side
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p class="mt-1 text-sm text-gray-600 dark:text-gray-200">
|
||||||
|
Denne operasjonen er permanent og kan ikke angres. All data
|
||||||
|
knyttet til siden vil bli slettet. Hvis siden er satt som
|
||||||
|
hovedsiden, vil alle besøkende bli redirigert til brukersiden
|
||||||
|
(hvis brukeren er innlogget), eller innloggingsiden hvis
|
||||||
|
den besøkende ikke er autentisert, inntill du setter en ny
|
||||||
|
forside.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="mt-6 flex justify-end">
|
||||||
|
<SecondaryButton @click="closeDeleteModal()"> Avbryt </SecondaryButton>
|
||||||
|
|
||||||
|
<DangerButton
|
||||||
|
class="ml-3"
|
||||||
|
:class="{ 'opacity-25': deleteForm.processing }"
|
||||||
|
:disabled="deleteForm.processing"
|
||||||
|
@click="deletePage"
|
||||||
|
>
|
||||||
|
Slett side
|
||||||
|
</DangerButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Head title="Sidebygger" />
|
||||||
|
|
||||||
|
<AuthenticatedLayout>
|
||||||
|
<template #header>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div>
|
||||||
|
<h2 class="font-semibold text-xl text-gray-800 leading-tight dark:text-gray-400">Administrering av sider</h2>
|
||||||
|
<h4 class="text-sm mt-2 text-gray-800 leading-tight dark:text-gray-400">Her kan du opprette en ny, eller administrere eksisterende sider</h4>
|
||||||
|
</div>
|
||||||
|
<Link :href="route('page-builder.landing-page.create')" v-if="hasPermission('create-article')" class="relative inline-flex items-center justify-center p-0.5 mb-2 mr-2 overflow-hidden text-sm font-medium text-gray-900 rounded-lg group bg-gradient-to-br from-cyan-500 to-blue-500 group-hover:from-cyan-500 group-hover:to-blue-500 hover:text-white dark:text-white focus:ring-4 focus:outline-none focus:ring-cyan-200 dark:focus:ring-cyan-800">
|
||||||
|
<span class="flex items-center relative px-5 py-2.5 transition-all ease-in duration-75 bg-white dark:bg-gray-700 rounded-md group-hover:bg-opacity-0">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 -960 960 960" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 mr-2">
|
||||||
|
<path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h440l200 200v440q0 33-23.5 56.5T760-120H200Zm0-80h560v-400H600v-160H200v560Zm80-80h400v-80H280v80Zm0-320h200v-80H280v80Zm0 160h400v-80H280v80Zm-80-320v160-160 560-560Z" />
|
||||||
|
</svg>
|
||||||
|
Ny side
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-4">
|
||||||
|
<div
|
||||||
|
v-for="page in builtPages"
|
||||||
|
:key="page.id"
|
||||||
|
class="flex flex-col items-center bg-white border border-gray-200 rounded-lg shadow-sm md:flex-row md:max-w-xl dark:border-gray-700 dark:bg-gray-800"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col md:w-48 w-full rounded-t-lg md:rounded-none md:rounded-s-lg overflow-hidden">
|
||||||
|
<img
|
||||||
|
v-for="(thumb, index) in getThumbs(page)"
|
||||||
|
:key="index"
|
||||||
|
:src="thumb"
|
||||||
|
alt="Forhåndsvisning"
|
||||||
|
class="object-cover w-full h-24 md:h-24 border-b dark:border-gray-700"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col justify-between p-4 leading-normal h-full w-full">
|
||||||
|
<div>
|
||||||
|
<h3 class="mb-2 text-xl font-semibold tracking-tight text-gray-900 dark:text-white">{{ page.title }}</h3>
|
||||||
|
<p class="mb-3 font-normal text-gray-700 dark:text-gray-400">Av: {{ page.author.name }} — Revisjoner: {{ page.revisions_count }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end gap-2 mt-4">
|
||||||
|
<Link
|
||||||
|
v-if="page.activeRevision"
|
||||||
|
:href="route('page-builder.builder.edit', page.activeRevision.uuid)"
|
||||||
|
class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
|
||||||
|
>
|
||||||
|
Rediger
|
||||||
|
</Link>
|
||||||
|
<button
|
||||||
|
@click="openDeleteModal(page)"
|
||||||
|
class="text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900"
|
||||||
|
>
|
||||||
|
Slett
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AuthenticatedLayout>
|
||||||
|
</template>
|
296
resources/js/pages/Backend/PageBuilder/Preview.vue
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
<script setup>
|
||||||
|
import { Head, Link, router, usePage} from '@inertiajs/vue3';
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { gsap } from 'gsap';
|
||||||
|
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||||
|
import { ScrollToPlugin } from 'gsap/ScrollToPlugin';
|
||||||
|
import { on } from '@/Components/EventBus.vue';
|
||||||
|
|
||||||
|
import MainMenu from '@/Components/FrontPage/MenyComponent.vue';
|
||||||
|
import ExternalMainMenu from '@/Components/FrontPage/ExternalMenuComponent.vue';
|
||||||
|
import SmallHeader from '@/Components/FrontPage/SmallHeader.vue';
|
||||||
|
|
||||||
|
import HeroLogoTextRendered from '@/Components/Blocks/Heroes/HeroLogoTextRendered.vue';
|
||||||
|
|
||||||
|
import FAQListRendered from '@/Components/Blocks/FAQ/FAQListRendered.vue';
|
||||||
|
import FAQCollapseRendered from '@/Components/Blocks/FAQ/FAQCollapseRendered.vue';
|
||||||
|
import FAQCondensedRendered from '@/Components/Blocks/FAQ/FAQCondensedRendered.vue';
|
||||||
|
|
||||||
|
import TwoColumnTextRendered from '@/Components/Blocks/Text/TwoColumnTextRendered.vue';
|
||||||
|
|
||||||
|
import FrontPageMenuHeaderRendered from '@/Components/Blocks/Statics/FrontPageMenuHeaderRendered.vue';
|
||||||
|
import FrontPageSponsorsRendered from '@/Components/Blocks/Statics/FrontPageSponsorsRendered.vue';
|
||||||
|
import FrontPageMembershipInfoRendered from '@/Components/Blocks/Statics/FrontPageMembershipInfoRendered.vue';
|
||||||
|
import FrontPageNewsListRendered from '@/Components/Blocks/Statics/FrontPageNewsListRendered.vue';
|
||||||
|
import FrontPageEventsListRendered from '@/Components/Blocks/Statics/FrontPageEventsListRendered.vue';
|
||||||
|
import PageFooterRendered from '@/Components/Blocks/Statics/PageFooterRendered.vue';
|
||||||
|
|
||||||
|
const {
|
||||||
|
revision,
|
||||||
|
images,
|
||||||
|
blockData,
|
||||||
|
menuLinks
|
||||||
|
} = defineProps({
|
||||||
|
revision: { type: Object, required: true },
|
||||||
|
images: { type: Array, default: () => ([]) },
|
||||||
|
blockData: { type: Object, default: () => ({}) },
|
||||||
|
menuLinks: { type: Object, default: () => ({}) }
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// Check if the url has the parameter key scrollTo
|
||||||
|
if (urlParam('scrollTo')) {
|
||||||
|
// Enable scrolling on the body and html elements
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
document.documentElement.style.overflow = 'auto';
|
||||||
|
// Get the value of the parameter
|
||||||
|
const scrollTo = urlParam('scrollTo');
|
||||||
|
|
||||||
|
// Scroll to the section with the id that matches the value of the parameter
|
||||||
|
gsap.to(window, {
|
||||||
|
duration: 1,
|
||||||
|
scrollTo: {
|
||||||
|
y: `#${scrollTo}`,
|
||||||
|
autoKill: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
gsap.registerPlugin(ScrollToPlugin, ScrollTrigger);
|
||||||
|
|
||||||
|
const useEventBus = ref(false);
|
||||||
|
const showMainMenu = ref(false);
|
||||||
|
const pageRef = ref();
|
||||||
|
const page = usePage();
|
||||||
|
const smallHeader = ref(null);
|
||||||
|
|
||||||
|
const showErrorModal = ref(false);
|
||||||
|
const errorStatus = ref('');
|
||||||
|
|
||||||
|
const closeErrorModal = () => {
|
||||||
|
showErrorModal.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lytt etter errorModal event fra Laravel
|
||||||
|
window.addEventListener('errorModal', (event) => {
|
||||||
|
showErrorModal.value = true;
|
||||||
|
errorStatus.value = event.detail.status;
|
||||||
|
});
|
||||||
|
|
||||||
|
/** Menu button animations */
|
||||||
|
const menuButton = ref(null);
|
||||||
|
|
||||||
|
const handleMenuButtonOver = () => {
|
||||||
|
gsap.set(menuButton.value, {
|
||||||
|
borderRadius: '0.375rem',
|
||||||
|
});
|
||||||
|
gsap.to(menuButton.value, {
|
||||||
|
duration: 0.2,
|
||||||
|
scale: 1.1,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMenuButtonOut = () => {
|
||||||
|
gsap.set(menuButton.value, {
|
||||||
|
borderRadius: '9999px',
|
||||||
|
});
|
||||||
|
gsap.to(menuButton.value, {
|
||||||
|
duration: 0.2,
|
||||||
|
scale: 1,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const clickMenuButton = () => {
|
||||||
|
showMainMenu.value = !showMainMenu.value;
|
||||||
|
|
||||||
|
if (showMainMenu.value) {
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
document.documentElement.style.overflow = 'hidden';
|
||||||
|
} else {
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
document.documentElement.style.overflow = 'auto';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Get a node value from json */
|
||||||
|
|
||||||
|
const extractMetaValue = (node, key) => {
|
||||||
|
let meta = JSON.parse(node.fs_meta);
|
||||||
|
|
||||||
|
return meta[key];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* formatDate
|
||||||
|
*
|
||||||
|
* Formats a date string to a Norwegian date format.
|
||||||
|
*
|
||||||
|
* @param {
|
||||||
|
* } dateString
|
||||||
|
*/
|
||||||
|
|
||||||
|
const formatDate = (dateString) => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
const day = ('0' + date.getDate()).slice(-2);
|
||||||
|
const month = ('0' + (date.getMonth() + 1)).slice(-2);
|
||||||
|
const year = date.getFullYear();
|
||||||
|
|
||||||
|
return `${day}/${month}/${year}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dateString
|
||||||
|
*
|
||||||
|
* Formats a date string to a Norwegian time format.
|
||||||
|
* @param {*} dateString
|
||||||
|
*/
|
||||||
|
|
||||||
|
const formatTime = (dateString) => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date.toLocaleTimeString('nb-NO', { hour: '2-digit', minute: '2-digit' });
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Get url parameters */
|
||||||
|
|
||||||
|
const urlParam = (paramKey) => {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
return url.searchParams.get(paramKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Denne funksjonen kalles fra lenker på siden for å
|
||||||
|
// Gi siden en myk fade ut effekt før den nye siden lastes
|
||||||
|
const loadLink = (url) => {
|
||||||
|
gsap.to(pageRef.value, {
|
||||||
|
duration: 1,
|
||||||
|
opacity: 0,
|
||||||
|
ease: 'power2.inOut',
|
||||||
|
onComplete: () => {
|
||||||
|
router.visit(url);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
HeroLogoTextRendered,
|
||||||
|
|
||||||
|
FAQListRendered,
|
||||||
|
FAQCollapseRendered,
|
||||||
|
FAQCondensedRendered,
|
||||||
|
|
||||||
|
TwoColumnTextRendered,
|
||||||
|
|
||||||
|
FrontPageMenuHeaderRendered,
|
||||||
|
FrontPageSponsorsRendered,
|
||||||
|
FrontPageMembershipInfoRendered,
|
||||||
|
FrontPageNewsListRendered,
|
||||||
|
FrontPageEventsListRendered,
|
||||||
|
PageFooterRendered
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Eventbus listeners */
|
||||||
|
|
||||||
|
on('linkClicked', (payload) => {
|
||||||
|
if (payload === 'om' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
gsap.to(window, {
|
||||||
|
duration: 1,
|
||||||
|
scrollTo: {
|
||||||
|
y: '#content',
|
||||||
|
autoKill: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (payload === 'arrangementer' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
gsap.to(window, {
|
||||||
|
duration: 1,
|
||||||
|
scrollTo: {
|
||||||
|
y: '#events',
|
||||||
|
autoKill: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (payload === 'nyheter' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
gsap.to(window, {
|
||||||
|
duration: 1,
|
||||||
|
scrollTo: {
|
||||||
|
y: '#intro',
|
||||||
|
autoKill: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (payload === 'sponsor' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
gsap.to(window, {
|
||||||
|
duration: 1,
|
||||||
|
scrollTo: {
|
||||||
|
y: '#sponsors-intro',
|
||||||
|
autoKill: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (payload === 'medlem' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
gsap.to(window, {
|
||||||
|
duration: 1,
|
||||||
|
scrollTo: {
|
||||||
|
y: '#membership',
|
||||||
|
autoKill: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (payload === 'medlemside' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
loadLink(route('dashboard'));
|
||||||
|
} else if (payload === 'loggpaa' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
loadLink(route('login'));
|
||||||
|
} else if (payload === 'registrer' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
loadLink(route('register'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
on('eventBusActive', (payload) => {
|
||||||
|
useEventBus.value = payload;
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Head>
|
||||||
|
<title>{{ revision.title }}</title>
|
||||||
|
</Head>
|
||||||
|
|
||||||
|
<div ref="pageRef" class="min-h-screen w-full bg-black">
|
||||||
|
<template v-if="revision.page.main"> <!-- Show Main menu if the current page is the front page (main page) -->
|
||||||
|
<MainMenu v-if="showMainMenu" :active="showMainMenu" :pageSettings="page.props.pageSettings" :menuLinks="menuLinks" />
|
||||||
|
</template>
|
||||||
|
<template v-else> <!-- Show the external main menu, if the current page is NOT the front page (main page) -->
|
||||||
|
<ExternalMainMenu v-if="showMainMenu" :active="showMainMenu" :pageSettings="page.props.pageSettings" class="z-40" />
|
||||||
|
</template>
|
||||||
|
<SmallHeader />
|
||||||
|
|
||||||
|
<!-- Hovedmeny knapp -->
|
||||||
|
<div class="fixed top-0 right-0 p-4 z-50">
|
||||||
|
<button ref="menuButton" @click="clickMenuButton" @mouseover="handleMenuButtonOver" @mouseout="handleMenuButtonOut" class="p-2 text-white rounded-full shadow-md shadow-black" :class="{'bg-sky-600': showMainMenu, 'bg-green-700': !showMainMenu }">
|
||||||
|
<svg v-if="showMainMenu" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<svg v-else xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Komponentrendring -->
|
||||||
|
<component
|
||||||
|
v-for="block in revision.content"
|
||||||
|
:key="block.uuid"
|
||||||
|
:images="images"
|
||||||
|
:is="components[block.renderComponentName]"
|
||||||
|
:block="block"
|
||||||
|
:blockData="blockData"
|
||||||
|
:frontpage="revision.page.main"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
310
resources/js/pages/Root.vue
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
<script setup>
|
||||||
|
import { Head, Link, router, usePage} from '@inertiajs/vue3';
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { gsap } from 'gsap';
|
||||||
|
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||||
|
import { ScrollToPlugin } from 'gsap/ScrollToPlugin';
|
||||||
|
import { on } from '@/Components/EventBus.vue';
|
||||||
|
|
||||||
|
import MainMenu from '@/Components/FrontPage/MenyComponent.vue';
|
||||||
|
import ExternalMainMenu from '@/Components/FrontPage/ExternalMenuComponent.vue';
|
||||||
|
import SmallHeader from '@/Components/FrontPage/SmallHeader.vue';
|
||||||
|
|
||||||
|
import HeroLogoTextRendered from '@/Components/Blocks/Heroes/HeroLogoTextRendered.vue';
|
||||||
|
|
||||||
|
import FAQListRendered from '@/Components/Blocks/FAQ/FAQListRendered.vue';
|
||||||
|
import FAQCollapseRendered from '@/Components/Blocks/FAQ/FAQCollapseRendered.vue';
|
||||||
|
import FAQCondensedRendered from '@/Components/Blocks/FAQ/FAQCondensedRendered.vue';
|
||||||
|
|
||||||
|
import TwoColumnTextRendered from '@/Components/Blocks/Text/TwoColumnTextRendered.vue';
|
||||||
|
|
||||||
|
import FrontPageMenuHeaderRendered from '@/Components/Blocks/Statics/FrontPageMenuHeaderRendered.vue';
|
||||||
|
import FrontPageSponsorsRendered from '@/Components/Blocks/Statics/FrontPageSponsorsRendered.vue';
|
||||||
|
import FrontPageMembershipInfoRendered from '@/Components/Blocks/Statics/FrontPageMembershipInfoRendered.vue';
|
||||||
|
import FrontPageNewsListRendered from '@/Components/Blocks/Statics/FrontPageNewsListRendered.vue';
|
||||||
|
import FrontPageEventsListRendered from '@/Components/Blocks/Statics/FrontPageEventsListRendered.vue';
|
||||||
|
import PageFooterRendered from '@/Components/Blocks/Statics/PageFooterRendered.vue';
|
||||||
|
|
||||||
|
const {
|
||||||
|
revision,
|
||||||
|
images,
|
||||||
|
blockData,
|
||||||
|
menuLinks
|
||||||
|
} = defineProps({
|
||||||
|
revision: { type: Object, required: true },
|
||||||
|
images: { type: Array, default: () => ([]) },
|
||||||
|
blockData: { type: Object, default: () => ({}) },
|
||||||
|
menuLinks: { type: Object, default: () => ({}) }
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// Check if the url has the parameter key scrollTo
|
||||||
|
if (urlParam('scrollTo')) {
|
||||||
|
// Enable scrolling on the body and html elements
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
document.documentElement.style.overflow = 'auto';
|
||||||
|
// Get the value of the parameter
|
||||||
|
const scrollTo = urlParam('scrollTo');
|
||||||
|
|
||||||
|
// Scroll to the section with the id that matches the value of the parameter
|
||||||
|
gsap.to(window, {
|
||||||
|
duration: 1,
|
||||||
|
scrollTo: {
|
||||||
|
y: `#${scrollTo}`,
|
||||||
|
autoKill: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
gsap.registerPlugin(ScrollToPlugin, ScrollTrigger);
|
||||||
|
|
||||||
|
const useEventBus = ref(false);
|
||||||
|
const showMainMenu = ref(false);
|
||||||
|
const pageRef = ref();
|
||||||
|
const page = usePage();
|
||||||
|
const smallHeader = ref(null);
|
||||||
|
|
||||||
|
const showErrorModal = ref(false);
|
||||||
|
const errorStatus = ref('');
|
||||||
|
|
||||||
|
const closeErrorModal = () => {
|
||||||
|
showErrorModal.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lytt etter errorModal event fra Laravel
|
||||||
|
window.addEventListener('errorModal', (event) => {
|
||||||
|
showErrorModal.value = true;
|
||||||
|
errorStatus.value = event.detail.status;
|
||||||
|
});
|
||||||
|
|
||||||
|
/** Menu button animations */
|
||||||
|
const menuButton = ref(null);
|
||||||
|
|
||||||
|
const handleMenuButtonOver = () => {
|
||||||
|
gsap.set(menuButton.value, {
|
||||||
|
borderRadius: '0.375rem',
|
||||||
|
});
|
||||||
|
gsap.to(menuButton.value, {
|
||||||
|
duration: 0.2,
|
||||||
|
scale: 1.1,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMenuButtonOut = () => {
|
||||||
|
gsap.set(menuButton.value, {
|
||||||
|
borderRadius: '9999px',
|
||||||
|
});
|
||||||
|
gsap.to(menuButton.value, {
|
||||||
|
duration: 0.2,
|
||||||
|
scale: 1,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const clickMenuButton = () => {
|
||||||
|
showMainMenu.value = !showMainMenu.value;
|
||||||
|
|
||||||
|
if (showMainMenu.value) {
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
document.documentElement.style.overflow = 'hidden';
|
||||||
|
} else {
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
document.documentElement.style.overflow = 'auto';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Get a node value from json */
|
||||||
|
|
||||||
|
const extractMetaValue = (node, key) => {
|
||||||
|
let meta = JSON.parse(node.fs_meta);
|
||||||
|
|
||||||
|
return meta[key];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* formatDate
|
||||||
|
*
|
||||||
|
* Formats a date string to a Norwegian date format.
|
||||||
|
*
|
||||||
|
* @param {
|
||||||
|
* } dateString
|
||||||
|
*/
|
||||||
|
|
||||||
|
const formatDate = (dateString) => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
const day = ('0' + date.getDate()).slice(-2);
|
||||||
|
const month = ('0' + (date.getMonth() + 1)).slice(-2);
|
||||||
|
const year = date.getFullYear();
|
||||||
|
|
||||||
|
return `${day}/${month}/${year}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dateString
|
||||||
|
*
|
||||||
|
* Formats a date string to a Norwegian time format.
|
||||||
|
* @param {*} dateString
|
||||||
|
*/
|
||||||
|
|
||||||
|
const formatTime = (dateString) => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date.toLocaleTimeString('nb-NO', { hour: '2-digit', minute: '2-digit' });
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Get url parameters */
|
||||||
|
|
||||||
|
const urlParam = (paramKey) => {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
return url.searchParams.get(paramKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Denne funksjonen kalles fra lenker på siden for å
|
||||||
|
// Gi siden en myk fade ut effekt før den nye siden lastes
|
||||||
|
const loadLink = (url) => {
|
||||||
|
gsap.to(pageRef.value, {
|
||||||
|
duration: 1,
|
||||||
|
opacity: 0,
|
||||||
|
ease: 'power2.inOut',
|
||||||
|
onComplete: () => {
|
||||||
|
router.visit(url);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
HeroLogoTextRendered,
|
||||||
|
|
||||||
|
FAQListRendered,
|
||||||
|
FAQCollapseRendered,
|
||||||
|
FAQCondensedRendered,
|
||||||
|
|
||||||
|
TwoColumnTextRendered,
|
||||||
|
|
||||||
|
FrontPageMenuHeaderRendered,
|
||||||
|
FrontPageSponsorsRendered,
|
||||||
|
FrontPageMembershipInfoRendered,
|
||||||
|
FrontPageNewsListRendered,
|
||||||
|
FrontPageEventsListRendered,
|
||||||
|
PageFooterRendered
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Eventbus listeners */
|
||||||
|
|
||||||
|
on('linkClicked', (payload) => {
|
||||||
|
if (payload === 'om' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
gsap.to(window, {
|
||||||
|
duration: 1,
|
||||||
|
scrollTo: {
|
||||||
|
y: '#content',
|
||||||
|
autoKill: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (payload === 'arrangementer' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
gsap.to(window, {
|
||||||
|
duration: 1,
|
||||||
|
scrollTo: {
|
||||||
|
y: '#events',
|
||||||
|
autoKill: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (payload === 'nyheter' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
gsap.to(window, {
|
||||||
|
duration: 1,
|
||||||
|
scrollTo: {
|
||||||
|
y: '#intro',
|
||||||
|
autoKill: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (payload === 'sponsor' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
gsap.to(window, {
|
||||||
|
duration: 1,
|
||||||
|
scrollTo: {
|
||||||
|
y: '#sponsors-intro',
|
||||||
|
autoKill: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (payload === 'medlem' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
gsap.to(window, {
|
||||||
|
duration: 1,
|
||||||
|
scrollTo: {
|
||||||
|
y: '#membership',
|
||||||
|
autoKill: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (payload === 'medlemside' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
loadLink(route('dashboard'));
|
||||||
|
} else if (payload === 'loggpaa' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
loadLink(route('login'));
|
||||||
|
} else if (payload === 'registrer' && useEventBus.value) {
|
||||||
|
clickMenuButton();
|
||||||
|
loadLink(route('register'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
on('eventBusActive', (payload) => {
|
||||||
|
useEventBus.value = payload;
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Head>
|
||||||
|
<title>{{ revision.title }}</title>
|
||||||
|
<meta name="description" :content="page.props.pageSettings['site_description']" />
|
||||||
|
<meta name="keywords" :content="page.props.pageSettings['site_keywords']" />
|
||||||
|
<meta name="author" content="Arctic Software PolarPress" />
|
||||||
|
<meta name="robots" content="index, follow" />
|
||||||
|
<meta name="og:title" :content="`Forsiden - ${page.props.pageSettings['site_title']}`" />
|
||||||
|
<meta name="og:description" :content="page.props.pageSettings['site_description']" />
|
||||||
|
<meta name="og:image" content="/img/illustration-full.png" />
|
||||||
|
<meta name="og:url" :content="page.props.baseUrl" />
|
||||||
|
<meta name="og:site_name" :content="page.props.siteName" />
|
||||||
|
<meta name="og:type" content="website" />
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="og:locale" content="nb_NO" />
|
||||||
|
<meta name="og:locale:alternate" content="en_US" />
|
||||||
|
<meta name="og:imagevisiblity" content="all" />
|
||||||
|
</Head>
|
||||||
|
|
||||||
|
<div ref="pageRef" class="min-h-screen w-full bg-black">
|
||||||
|
<template v-if="revision.page.main"> <!-- Show Main menu if the current page is the front page (main page) -->
|
||||||
|
<MainMenu v-if="showMainMenu" :active="showMainMenu" :pageSettings="page.props.pageSettings" :menuLinks="menuLinks" />
|
||||||
|
</template>
|
||||||
|
<template v-else> <!-- Show the external main menu, if the current page is NOT the front page (main page) -->
|
||||||
|
<ExternalMainMenu v-if="showMainMenu" :active="showMainMenu" :pageSettings="page.props.pageSettings" class="z-40" />
|
||||||
|
</template>
|
||||||
|
<SmallHeader />
|
||||||
|
|
||||||
|
<!-- Hovedmeny knapp -->
|
||||||
|
<div class="fixed top-0 right-0 p-4 z-50">
|
||||||
|
<button ref="menuButton" @click="clickMenuButton" @mouseover="handleMenuButtonOver" @mouseout="handleMenuButtonOut" class="p-2 text-white rounded-full shadow-md shadow-black" :class="{'bg-sky-600': showMainMenu, 'bg-green-700': !showMainMenu }">
|
||||||
|
<svg v-if="showMainMenu" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<svg v-else xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Komponentrendring -->
|
||||||
|
<component
|
||||||
|
v-for="block in revision.content"
|
||||||
|
:key="block.uuid"
|
||||||
|
:images="images"
|
||||||
|
:is="components[block.renderComponentName]"
|
||||||
|
:block="block"
|
||||||
|
:blockData="blockData"
|
||||||
|
:frontpage="revision.page.main"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Head, Link } from '@inertiajs/vue3';
|
import { Head, Link } from '@inertiajs/vue3';
|
||||||
|
import PageLogo from '@/Components/ArcticFooterLogo.vue';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -12,23 +13,23 @@ import { Head, Link } from '@inertiajs/vue3';
|
|||||||
<nav class="flex items-center justify-end gap-4">
|
<nav class="flex items-center justify-end gap-4">
|
||||||
<Link
|
<Link
|
||||||
v-if="$page.props.auth.user"
|
v-if="$page.props.auth.user"
|
||||||
:href="route('dashboard')"
|
:href="route('page-builder.index')"
|
||||||
class="inline-block rounded-sm border border-[#19140035] px-5 py-1.5 text-sm leading-normal text-[#1b1b18] hover:border-[#1915014a] dark:border-[#3E3E3A] dark:text-[#EDEDEC] dark:hover:border-[#62605b]"
|
class="inline-block rounded-sm border border-[#19140035] px-5 py-1.5 text-sm leading-normal text-[#1b1b18] hover:border-[#1915014a] dark:border-[#3E3E3A] dark:text-[#EDEDEC] dark:hover:border-[#62605b]"
|
||||||
>
|
>
|
||||||
Dashboard
|
Sidebygger
|
||||||
</Link>
|
</Link>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<Link
|
<Link
|
||||||
:href="route('login')"
|
:href="route('login')"
|
||||||
class="inline-block rounded-sm border border-transparent px-5 py-1.5 text-sm leading-normal text-[#1b1b18] hover:border-[#19140035] dark:text-[#EDEDEC] dark:hover:border-[#3E3E3A]"
|
class="inline-block rounded-sm border border-transparent px-5 py-1.5 text-sm leading-normal text-[#1b1b18] hover:border-[#19140035] dark:text-[#EDEDEC] dark:hover:border-[#3E3E3A]"
|
||||||
>
|
>
|
||||||
Log in
|
Logg på
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
:href="route('register')"
|
:href="route('register')"
|
||||||
class="inline-block rounded-sm border border-[#19140035] px-5 py-1.5 text-sm leading-normal text-[#1b1b18] hover:border-[#1915014a] dark:border-[#3E3E3A] dark:text-[#EDEDEC] dark:hover:border-[#62605b]"
|
class="inline-block rounded-sm border border-[#19140035] px-5 py-1.5 text-sm leading-normal text-[#1b1b18] hover:border-[#1915014a] dark:border-[#3E3E3A] dark:text-[#EDEDEC] dark:hover:border-[#62605b]"
|
||||||
>
|
>
|
||||||
Register
|
Registrer konto
|
||||||
</Link>
|
</Link>
|
||||||
</template>
|
</template>
|
||||||
</nav>
|
</nav>
|
||||||
@ -38,9 +39,11 @@ import { Head, Link } from '@inertiajs/vue3';
|
|||||||
<div
|
<div
|
||||||
class="flex-1 rounded-bl-lg rounded-br-lg bg-white p-6 pb-12 text-[13px] leading-[20px] shadow-[inset_0px_0px_0px_1px_rgba(26,26,0,0.16)] dark:bg-[#161615] dark:text-[#EDEDEC] dark:shadow-[inset_0px_0px_0px_1px_#fffaed2d] lg:rounded-br-none lg:rounded-tl-lg lg:p-20"
|
class="flex-1 rounded-bl-lg rounded-br-lg bg-white p-6 pb-12 text-[13px] leading-[20px] shadow-[inset_0px_0px_0px_1px_rgba(26,26,0,0.16)] dark:bg-[#161615] dark:text-[#EDEDEC] dark:shadow-[inset_0px_0px_0px_1px_#fffaed2d] lg:rounded-br-none lg:rounded-tl-lg lg:p-20"
|
||||||
>
|
>
|
||||||
<h1 class="mb-1 font-medium">Let's get started</h1>
|
<h1 class="mb-1 font-medium">Kom igang med PolarPress sidebygger</h1>
|
||||||
<p class="mb-2 text-[#706f6c] dark:text-[#A1A09A]">
|
<p class="mb-2 text-[#706f6c] dark:text-[#A1A09A]">
|
||||||
Laravel has an incredibly rich ecosystem. <br />We suggest starting with the following.
|
PolarPress er et innholdsgenereringssystem (CMS) utviklet av Arctic Software A/S <br /><br />
|
||||||
|
Du kan bruke dette lokale utviklingsmiljøet for å utvikle og teste nye komponenter til sidebyggeren<br /><br />
|
||||||
|
For å komme igang foreslår vi at du starter med:
|
||||||
</p>
|
</p>
|
||||||
<ul class="mb-4 flex flex-col lg:mb-6">
|
<ul class="mb-4 flex flex-col lg:mb-6">
|
||||||
<li
|
<li
|
||||||
@ -54,13 +57,13 @@ import { Head, Link } from '@inertiajs/vue3';
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
Read the
|
Lese
|
||||||
<a
|
<a
|
||||||
href="https://laravel.com/docs"
|
href="https://git.arcticsoftware.no/arcticsoftware/polarpress-pagebuilder"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="ml-1 inline-flex items-center space-x-1 font-medium text-[#f53003] underline underline-offset-4 dark:text-[#FF4433]"
|
class="ml-1 inline-flex items-center space-x-1 font-medium text-[#f53003] underline underline-offset-4 dark:text-[#FF4433]"
|
||||||
>
|
>
|
||||||
<span>Documentation</span>
|
<span>dokumentasjonen</span>
|
||||||
<svg
|
<svg
|
||||||
width="{10}"
|
width="{10}"
|
||||||
height="{11}"
|
height="{11}"
|
||||||
@ -85,13 +88,13 @@ import { Head, Link } from '@inertiajs/vue3';
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
Watch video tutorials at
|
Bli med i vår
|
||||||
<a
|
<a
|
||||||
href="https://laracasts.com"
|
href="https://chat.zuul.no"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="ml-1 inline-flex items-center space-x-1 font-medium text-[#f53003] underline underline-offset-4 dark:text-[#FF4433]"
|
class="ml-1 inline-flex items-center space-x-1 font-medium text-[#f53003] underline underline-offset-4 dark:text-[#FF4433]"
|
||||||
>
|
>
|
||||||
<span>Laracasts</span>
|
<span>gruppechat</span>
|
||||||
<svg
|
<svg
|
||||||
width="{10}"
|
width="{10}"
|
||||||
height="{11}"
|
height="{11}"
|
||||||
@ -108,677 +111,25 @@ import { Head, Link } from '@inertiajs/vue3';
|
|||||||
</ul>
|
</ul>
|
||||||
<ul class="flex gap-3 text-sm leading-normal">
|
<ul class="flex gap-3 text-sm leading-normal">
|
||||||
<li>
|
<li>
|
||||||
<a
|
<Link
|
||||||
href="https://cloud.laravel.com"
|
:href="route('page-builder.index')"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="inline-block rounded-sm border border-black bg-[#1b1b18] px-5 py-1.5 text-sm leading-normal text-white hover:border-black hover:bg-black dark:border-[#eeeeec] dark:bg-[#eeeeec] dark:text-[#1C1C1A] dark:hover:border-white dark:hover:bg-white"
|
class="inline-block rounded-sm border border-black bg-[#1b1b18] px-5 py-1.5 text-sm leading-normal text-white hover:border-black hover:bg-black dark:border-[#eeeeec] dark:bg-[#eeeeec] dark:text-[#1C1C1A] dark:hover:border-white dark:hover:bg-white"
|
||||||
>
|
>
|
||||||
Deploy now
|
Start her
|
||||||
</a>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="relative -mb-px aspect-335/376 w-full shrink-0 overflow-hidden rounded-t-lg bg-[#fff2f2] dark:bg-[#1D0002] lg:-ml-px lg:mb-0 lg:aspect-auto lg:w-[438px] lg:rounded-r-lg lg:rounded-t-none"
|
class="relative -mb-px aspect-335/376 w-full shrink-0 overflow-hidden rounded-t-lg bg-white dark:bg-gray-900 lg:-ml-px lg:mb-0 lg:aspect-auto lg:w-[438px] lg:rounded-r-lg lg:rounded-t-none"
|
||||||
>
|
>
|
||||||
<svg
|
|
||||||
class="duration-750 starting:translate-y-6 starting:opacity-0 w-full max-w-none translate-y-0 text-[#F53003] opacity-100 transition-all dark:text-[#F61500]"
|
|
||||||
viewBox="0 0 438 104"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path d="M17.2036 -3H0V102.197H49.5189V86.7187H17.2036V-3Z" fill="currentColor" />
|
|
||||||
<path
|
|
||||||
d="M110.256 41.6337C108.061 38.1275 104.945 35.3731 100.905 33.3681C96.8667 31.3647 92.8016 30.3618 88.7131 30.3618C83.4247 30.3618 78.5885 31.3389 74.201 33.2923C69.8111 35.2456 66.0474 37.928 62.9059 41.3333C59.7643 44.7401 57.3198 48.6726 55.5754 53.1293C53.8287 57.589 52.9572 62.274 52.9572 67.1813C52.9572 72.1925 53.8287 76.8995 55.5754 81.3069C57.3191 85.7173 59.7636 89.6241 62.9059 93.0293C66.0474 96.4361 69.8119 99.1155 74.201 101.069C78.5885 103.022 83.4247 103.999 88.7131 103.999C92.8016 103.999 96.8667 102.997 100.905 100.994C104.945 98.9911 108.061 96.2359 110.256 92.7282V102.195H126.563V32.1642H110.256V41.6337ZM108.76 75.7472C107.762 78.4531 106.366 80.8078 104.572 82.8112C102.776 84.8161 100.606 86.4183 98.0637 87.6206C95.5202 88.823 92.7004 89.4238 89.6103 89.4238C86.5178 89.4238 83.7252 88.823 81.2324 87.6206C78.7388 86.4183 76.5949 84.8161 74.7998 82.8112C73.004 80.8078 71.6319 78.4531 70.6856 75.7472C69.7356 73.0421 69.2644 70.1868 69.2644 67.1821C69.2644 64.1758 69.7356 61.3205 70.6856 58.6154C71.6319 55.9102 73.004 53.5571 74.7998 51.5522C76.5949 49.5495 78.738 47.9451 81.2324 46.7427C83.7252 45.5404 86.5178 44.9396 89.6103 44.9396C92.7012 44.9396 95.5202 45.5404 98.0637 46.7427C100.606 47.9451 102.776 49.5487 104.572 51.5522C106.367 53.5571 107.762 55.9102 108.76 58.6154C109.756 61.3205 110.256 64.1758 110.256 67.1821C110.256 70.1868 109.756 73.0421 108.76 75.7472Z"
|
|
||||||
fill="currentColor"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M242.805 41.6337C240.611 38.1275 237.494 35.3731 233.455 33.3681C229.416 31.3647 225.351 30.3618 221.262 30.3618C215.974 30.3618 211.138 31.3389 206.75 33.2923C202.36 35.2456 198.597 37.928 195.455 41.3333C192.314 44.7401 189.869 48.6726 188.125 53.1293C186.378 57.589 185.507 62.274 185.507 67.1813C185.507 72.1925 186.378 76.8995 188.125 81.3069C189.868 85.7173 192.313 89.6241 195.455 93.0293C198.597 96.4361 202.361 99.1155 206.75 101.069C211.138 103.022 215.974 103.999 221.262 103.999C225.351 103.999 229.416 102.997 233.455 100.994C237.494 98.9911 240.611 96.2359 242.805 92.7282V102.195H259.112V32.1642H242.805V41.6337ZM241.31 75.7472C240.312 78.4531 238.916 80.8078 237.122 82.8112C235.326 84.8161 233.156 86.4183 230.614 87.6206C228.07 88.823 225.251 89.4238 222.16 89.4238C219.068 89.4238 216.275 88.823 213.782 87.6206C211.289 86.4183 209.145 84.8161 207.35 82.8112C205.554 80.8078 204.182 78.4531 203.236 75.7472C202.286 73.0421 201.814 70.1868 201.814 67.1821C201.814 64.1758 202.286 61.3205 203.236 58.6154C204.182 55.9102 205.554 53.5571 207.35 51.5522C209.145 49.5495 211.288 47.9451 213.782 46.7427C216.275 45.5404 219.068 44.9396 222.16 44.9396C225.251 44.9396 228.07 45.5404 230.614 46.7427C233.156 47.9451 235.326 49.5487 237.122 51.5522C238.917 53.5571 240.312 55.9102 241.31 58.6154C242.306 61.3205 242.806 64.1758 242.806 67.1821C242.805 70.1868 242.305 73.0421 241.31 75.7472Z"
|
|
||||||
fill="currentColor"
|
|
||||||
/>
|
|
||||||
<path d="M438 -3H421.694V102.197H438V-3Z" fill="currentColor" />
|
|
||||||
<path d="M139.43 102.197H155.735V48.2834H183.712V32.1665H139.43V102.197Z" fill="currentColor" />
|
|
||||||
<path
|
|
||||||
d="M324.49 32.1665L303.995 85.794L283.498 32.1665H266.983L293.748 102.197H314.242L341.006 32.1665H324.49Z"
|
|
||||||
fill="currentColor"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M376.571 30.3656C356.603 30.3656 340.797 46.8497 340.797 67.1828C340.797 89.6597 356.094 104 378.661 104C391.29 104 399.354 99.1488 409.206 88.5848L398.189 80.0226C398.183 80.031 389.874 90.9895 377.468 90.9895C363.048 90.9895 356.977 79.3111 356.977 73.269H411.075C413.917 50.1328 398.775 30.3656 376.571 30.3656ZM357.02 61.0967C357.145 59.7487 359.023 43.3761 376.442 43.3761C393.861 43.3761 395.978 59.7464 396.099 61.0967H357.02Z"
|
|
||||||
fill="currentColor"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<svg
|
|
||||||
class="relative -ml-8 -mt-[4.9rem] w-[448px] max-w-none dark:hidden lg:-mt-[6.6rem] lg:ml-0"
|
|
||||||
viewBox="0 0 440 376"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<g class="duration-750 starting:translate-y-4 starting:opacity-0 translate-y-0 opacity-100 transition-all delay-300">
|
|
||||||
<path
|
|
||||||
d="M188.263 355.73L188.595 355.73C195.441 348.845 205.766 339.761 219.569 328.477C232.93 317.193 242.978 308.205 249.714 301.511C256.34 294.626 260.867 287.358 263.296 279.708C265.725 272.058 264.565 264.121 259.816 255.896C254.516 246.716 247.062 239.352 237.454 233.805C227.957 228.067 217.908 225.198 207.307 225.198C196.927 225.197 190.136 227.97 186.934 233.516C183.621 238.872 184.726 246.331 190.247 255.894L125.647 255.891C116.371 239.825 112.395 225.481 113.72 212.858C115.265 200.235 121.559 190.481 132.602 183.596C143.754 176.52 158.607 172.982 177.159 172.983C196.594 172.984 215.863 176.523 234.968 183.6C253.961 190.486 271.299 200.241 286.98 212.864C302.661 225.488 315.14 239.833 324.416 255.899C333.03 270.817 336.841 283.918 335.847 295.203C335.075 306.487 331.376 316.336 324.75 324.751C318.346 333.167 308.408 343.494 294.936 355.734L377.094 355.737L405.917 405.656L217.087 405.649L188.263 355.73Z"
|
|
||||||
fill="black"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M9.11884 226.339L-13.7396 226.338L-42.7286 176.132L43.0733 176.135L175.595 405.649L112.651 405.647L9.11884 226.339Z"
|
|
||||||
fill="black"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M188.263 355.73L188.595 355.73C195.441 348.845 205.766 339.761 219.569 328.477C232.93 317.193 242.978 308.205 249.714 301.511C256.34 294.626 260.867 287.358 263.296 279.708C265.725 272.058 264.565 264.121 259.816 255.896C254.516 246.716 247.062 239.352 237.454 233.805C227.957 228.067 217.908 225.198 207.307 225.198C196.927 225.197 190.136 227.97 186.934 233.516C183.621 238.872 184.726 246.331 190.247 255.894L125.647 255.891C116.371 239.825 112.395 225.481 113.72 212.858C115.265 200.235 121.559 190.481 132.602 183.596C143.754 176.52 158.607 172.982 177.159 172.983C196.594 172.984 215.863 176.523 234.968 183.6C253.961 190.486 271.299 200.241 286.98 212.864C302.661 225.488 315.14 239.833 324.416 255.899C333.03 270.817 336.841 283.918 335.847 295.203C335.075 306.487 331.376 316.336 324.75 324.751C318.346 333.167 308.408 343.494 294.936 355.734L377.094 355.737L405.917 405.656L217.087 405.649L188.263 355.73Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M9.11884 226.339L-13.7396 226.338L-42.7286 176.132L43.0733 176.135L175.595 405.649L112.651 405.647L9.11884 226.339Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M204.592 327.449L204.923 327.449C211.769 320.564 222.094 311.479 235.897 300.196C249.258 288.912 259.306 279.923 266.042 273.23C272.668 266.345 277.195 259.077 279.624 251.427C282.053 243.777 280.893 235.839 276.145 227.615C270.844 218.435 263.39 211.071 253.782 205.524C244.285 199.786 234.236 196.917 223.635 196.916C213.255 196.916 206.464 199.689 203.262 205.235C199.949 210.59 201.054 218.049 206.575 227.612L141.975 227.61C132.699 211.544 128.723 197.2 130.048 184.577C131.593 171.954 137.887 162.2 148.93 155.315C160.083 148.239 174.935 144.701 193.487 144.702C212.922 144.703 232.192 148.242 251.296 155.319C270.289 162.205 287.627 171.96 303.308 184.583C318.989 197.207 331.468 211.552 340.745 227.618C349.358 242.536 353.169 255.637 352.175 266.921C351.403 278.205 347.704 288.055 341.078 296.47C334.674 304.885 324.736 315.213 311.264 327.453L393.422 327.456L422.246 377.375L233.415 377.368L204.592 327.449Z"
|
|
||||||
fill="#F8B803"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M25.447 198.058L2.58852 198.057L-26.4005 147.851L59.4015 147.854L191.923 377.368L128.979 377.365L25.447 198.058Z"
|
|
||||||
fill="#F8B803"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M204.592 327.449L204.923 327.449C211.769 320.564 222.094 311.479 235.897 300.196C249.258 288.912 259.306 279.923 266.042 273.23C272.668 266.345 277.195 259.077 279.624 251.427C282.053 243.777 280.893 235.839 276.145 227.615C270.844 218.435 263.39 211.071 253.782 205.524C244.285 199.786 234.236 196.917 223.635 196.916C213.255 196.916 206.464 199.689 203.262 205.235C199.949 210.59 201.054 218.049 206.575 227.612L141.975 227.61C132.699 211.544 128.723 197.2 130.048 184.577C131.593 171.954 137.887 162.2 148.93 155.315C160.083 148.239 174.935 144.701 193.487 144.702C212.922 144.703 232.192 148.242 251.296 155.319C270.289 162.205 287.627 171.96 303.308 184.583C318.989 197.207 331.468 211.552 340.745 227.618C349.358 242.536 353.169 255.637 352.175 266.921C351.403 278.205 347.704 288.055 341.078 296.47C334.674 304.885 324.736 315.213 311.264 327.453L393.422 327.456L422.246 377.375L233.415 377.368L204.592 327.449Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M25.447 198.058L2.58852 198.057L-26.4005 147.851L59.4015 147.854L191.923 377.368L128.979 377.365L25.447 198.058Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
:style="{ mixBlendMode: 'hard-light' }"
|
|
||||||
class="duration-750 starting:translate-y-4 starting:opacity-0 translate-y-0 opacity-100 transition-all delay-300"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M217.342 305.363L217.673 305.363C224.519 298.478 234.844 289.393 248.647 278.11C262.008 266.826 272.056 257.837 278.792 251.144C285.418 244.259 289.945 236.991 292.374 229.341C294.803 221.691 293.643 213.753 288.895 205.529C283.594 196.349 276.14 188.985 266.532 183.438C257.035 177.7 246.986 174.831 236.385 174.83C226.005 174.83 219.214 177.603 216.012 183.149C212.699 188.504 213.804 195.963 219.325 205.527L154.725 205.524C145.449 189.458 141.473 175.114 142.798 162.491C144.343 149.868 150.637 140.114 161.68 133.229C172.833 126.153 187.685 122.615 206.237 122.616C225.672 122.617 244.942 126.156 264.046 133.233C283.039 140.119 300.377 149.874 316.058 162.497C331.739 175.121 344.218 189.466 353.495 205.532C362.108 220.45 365.919 233.551 364.925 244.835C364.153 256.12 360.454 265.969 353.828 274.384C347.424 282.799 337.486 293.127 324.014 305.367L406.172 305.37L434.996 355.289L246.165 355.282L217.342 305.363Z"
|
|
||||||
fill="#F0ACB8"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M38.197 175.972L15.3385 175.971L-13.6505 125.765L72.1515 125.768L204.673 355.282L141.729 355.279L38.197 175.972Z"
|
|
||||||
fill="#F0ACB8"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M217.342 305.363L217.673 305.363C224.519 298.478 234.844 289.393 248.647 278.11C262.008 266.826 272.056 257.837 278.792 251.144C285.418 244.259 289.945 236.991 292.374 229.341C294.803 221.691 293.643 213.753 288.895 205.529C283.594 196.349 276.14 188.985 266.532 183.438C257.035 177.7 246.986 174.831 236.385 174.83C226.005 174.83 219.214 177.603 216.012 183.149C212.699 188.504 213.804 195.963 219.325 205.527L154.725 205.524C145.449 189.458 141.473 175.114 142.798 162.491C144.343 149.868 150.637 140.114 161.68 133.229C172.833 126.153 187.685 122.615 206.237 122.616C225.672 122.617 244.942 126.156 264.046 133.233C283.039 140.119 300.377 149.874 316.058 162.497C331.739 175.121 344.218 189.466 353.495 205.532C362.108 220.45 365.919 233.551 364.925 244.835C364.153 256.12 360.454 265.969 353.828 274.384C347.424 282.799 337.486 293.127 324.014 305.367L406.172 305.37L434.996 355.289L246.165 355.282L217.342 305.363Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M38.197 175.972L15.3385 175.971L-13.6505 125.765L72.1515 125.768L204.673 355.282L141.729 355.279L38.197 175.972Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
:style="{ mixBlendMode: 'plus-darker' }"
|
|
||||||
class="duration-750 starting:translate-y-4 starting:opacity-0 translate-y-0 opacity-100 transition-all delay-300"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M230.951 281.792L231.282 281.793C238.128 274.907 248.453 265.823 262.256 254.539C275.617 243.256 285.666 234.267 292.402 227.573C299.027 220.688 303.554 213.421 305.983 205.771C308.412 198.12 307.253 190.183 302.504 181.959C297.203 172.778 289.749 165.415 280.142 159.868C270.645 154.13 260.596 151.26 249.995 151.26C239.615 151.26 232.823 154.033 229.621 159.579C226.309 164.934 227.413 172.393 232.935 181.956L168.335 181.954C159.058 165.888 155.082 151.543 156.407 138.92C157.953 126.298 164.247 116.544 175.289 109.659C186.442 102.583 201.294 99.045 219.846 99.0457C239.281 99.0464 258.551 102.585 277.655 109.663C296.649 116.549 313.986 126.303 329.667 138.927C345.349 151.551 357.827 165.895 367.104 181.961C375.718 196.88 379.528 209.981 378.535 221.265C377.762 232.549 374.063 242.399 367.438 250.814C361.033 259.229 351.095 269.557 337.624 281.796L419.782 281.8L448.605 331.719L259.774 331.712L230.951 281.792Z"
|
|
||||||
fill="#F3BEC7"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M51.8063 152.402L28.9479 152.401L-0.0411453 102.195L85.7608 102.198L218.282 331.711L155.339 331.709L51.8063 152.402Z"
|
|
||||||
fill="#F3BEC7"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M230.951 281.792L231.282 281.793C238.128 274.907 248.453 265.823 262.256 254.539C275.617 243.256 285.666 234.267 292.402 227.573C299.027 220.688 303.554 213.421 305.983 205.771C308.412 198.12 307.253 190.183 302.504 181.959C297.203 172.778 289.749 165.415 280.142 159.868C270.645 154.13 260.596 151.26 249.995 151.26C239.615 151.26 232.823 154.033 229.621 159.579C226.309 164.934 227.413 172.393 232.935 181.956L168.335 181.954C159.058 165.888 155.082 151.543 156.407 138.92C157.953 126.298 164.247 116.544 175.289 109.659C186.442 102.583 201.294 99.045 219.846 99.0457C239.281 99.0464 258.551 102.585 277.655 109.663C296.649 116.549 313.986 126.303 329.667 138.927C345.349 151.551 357.827 165.895 367.104 181.961C375.718 196.88 379.528 209.981 378.535 221.265C377.762 232.549 374.063 242.399 367.438 250.814C361.033 259.229 351.095 269.557 337.624 281.796L419.782 281.8L448.605 331.719L259.774 331.712L230.951 281.792Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M51.8063 152.402L28.9479 152.401L-0.0411453 102.195L85.7608 102.198L218.282 331.711L155.339 331.709L51.8063 152.402Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
<g class="duration-750 starting:translate-y-4 starting:opacity-0 translate-y-0 opacity-100 transition-all delay-300">
|
|
||||||
<path
|
|
||||||
d="M188.467 355.363L188.798 355.363C195.644 348.478 205.969 339.393 219.772 328.11C233.133 316.826 243.181 307.837 249.917 301.144C253.696 297.217 256.792 293.166 259.205 288.991C261.024 285.845 262.455 282.628 263.499 279.341C265.928 271.691 264.768 263.753 260.02 255.529C254.719 246.349 247.265 238.985 237.657 233.438C228.16 227.7 218.111 224.831 207.51 224.83C197.13 224.83 190.339 227.603 187.137 233.149C183.824 238.504 184.929 245.963 190.45 255.527L125.851 255.524C116.574 239.458 112.598 225.114 113.923 212.491C114.615 206.836 116.261 201.756 118.859 197.253C122.061 191.704 126.709 187.03 132.805 183.229C143.958 176.153 158.81 172.615 177.362 172.616C196.797 172.617 216.067 176.156 235.171 183.233C254.164 190.119 271.502 199.874 287.183 212.497C302.864 225.121 315.343 239.466 324.62 255.532C333.233 270.45 337.044 283.551 336.05 294.835C335.46 303.459 333.16 311.245 329.151 318.194C327.915 320.337 326.515 322.4 324.953 324.384C318.549 332.799 308.611 343.127 295.139 355.367L377.297 355.37L406.121 405.289L217.29 405.282L188.467 355.363Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M9.32197 225.972L-13.5365 225.971L-42.5255 175.765L43.2765 175.768L175.798 405.282L112.854 405.279L9.32197 225.972Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M345.247 111.915C329.566 99.2919 312.229 89.5371 293.235 82.6512L235.167 183.228C254.161 190.114 271.498 199.869 287.179 212.492L345.247 111.915Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M382.686 154.964C373.41 138.898 360.931 124.553 345.25 111.93L287.182 212.506C302.863 225.13 315.342 239.475 324.618 255.541L382.686 154.964Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M293.243 82.6472C274.139 75.57 254.869 72.031 235.434 72.0303L177.366 172.607C196.801 172.608 216.071 176.147 235.175 183.224L293.243 82.6472Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M394.118 194.257C395.112 182.973 391.301 169.872 382.688 154.953L324.619 255.53C333.233 270.448 337.044 283.55 336.05 294.834L394.118 194.257Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M235.432 72.0311C216.88 72.0304 202.027 75.5681 190.875 82.6442L132.806 183.221C143.959 176.145 158.812 172.607 177.363 172.608L235.432 72.0311Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M265.59 124.25C276.191 124.251 286.24 127.12 295.737 132.858L237.669 233.435C228.172 227.697 218.123 224.828 207.522 224.827L265.59 124.25Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M295.719 132.859C305.326 138.406 312.78 145.77 318.081 154.95L260.013 255.527C254.712 246.347 247.258 238.983 237.651 233.436L295.719 132.859Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M387.218 217.608C391.227 210.66 393.527 202.874 394.117 194.25L336.049 294.827C335.459 303.451 333.159 311.237 329.15 318.185L387.218 217.608Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M245.211 132.577C248.413 127.03 255.204 124.257 265.584 124.258L207.516 224.835C197.136 224.834 190.345 227.607 187.143 233.154L245.211 132.577Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M318.094 154.945C322.842 163.17 324.002 171.107 321.573 178.757L263.505 279.334C265.934 271.684 264.774 263.746 260.026 255.522L318.094 154.945Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M176.925 96.6737C180.127 91.1249 184.776 86.4503 190.871 82.6499L132.803 183.227C126.708 187.027 122.059 191.702 118.857 197.25L176.925 96.6737Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M387.226 217.606C385.989 219.749 384.59 221.813 383.028 223.797L324.96 324.373C326.522 322.39 327.921 320.326 329.157 318.183L387.226 217.606Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M317.269 188.408C319.087 185.262 320.519 182.045 321.562 178.758L263.494 279.335C262.451 282.622 261.019 285.839 259.201 288.985L317.269 188.408Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M245.208 132.573C241.895 137.928 243 145.387 248.522 154.95L190.454 255.527C184.932 245.964 183.827 238.505 187.14 233.15L245.208 132.573Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M176.93 96.6719C174.331 101.175 172.686 106.255 171.993 111.91L113.925 212.487C114.618 206.831 116.263 201.752 118.862 197.249L176.93 96.6719Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M317.266 188.413C314.853 192.589 311.757 196.64 307.978 200.566L249.91 301.143C253.689 297.216 256.785 293.166 259.198 288.99L317.266 188.413Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M464.198 304.708L435.375 254.789L377.307 355.366L406.13 405.285L464.198 304.708Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M353.209 254.787C366.68 242.548 376.618 232.22 383.023 223.805L324.955 324.382C318.55 332.797 308.612 343.124 295.141 355.364L353.209 254.787Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M435.37 254.787L353.212 254.784L295.144 355.361L377.302 355.364L435.37 254.787Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M183.921 154.947L248.521 154.95L190.453 255.527L125.853 255.524L183.921 154.947Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M171.992 111.914C170.668 124.537 174.643 138.881 183.92 154.947L125.852 255.524C116.575 239.458 112.599 225.114 113.924 212.491L171.992 111.914Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M307.987 200.562C301.251 207.256 291.203 216.244 277.842 227.528L219.774 328.105C233.135 316.821 243.183 307.832 249.919 301.139L307.987 200.562Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M15.5469 75.1797L44.5359 125.386L-13.5321 225.963L-42.5212 175.756L15.5469 75.1797Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M277.836 227.536C264.033 238.82 253.708 247.904 246.862 254.789L188.794 355.366C195.64 348.481 205.965 339.397 219.768 328.113L277.836 227.536Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M275.358 304.706L464.189 304.713L406.12 405.29L217.29 405.283L275.358 304.706Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M44.5279 125.39L67.3864 125.39L9.31834 225.967L-13.5401 225.966L44.5279 125.39Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M101.341 75.1911L233.863 304.705L175.795 405.282L43.2733 175.768L101.341 75.1911ZM15.5431 75.19L-42.525 175.767L43.277 175.77L101.345 75.1932L15.5431 75.19Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M246.866 254.784L246.534 254.784L188.466 355.361L188.798 355.361L246.866 254.784Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M246.539 254.781L275.362 304.701L217.294 405.277L188.471 355.358L246.539 254.781Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M67.3906 125.391L170.923 304.698L112.855 405.275L9.32257 225.967L67.3906 125.391Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M170.921 304.699L233.865 304.701L175.797 405.278L112.853 405.276L170.921 304.699Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
:style="{ mixBlendMode: 'hard-light' }"
|
|
||||||
class="duration-750 starting:translate-y-4 starting:opacity-0 translate-y-0 opacity-100 transition-all delay-300"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M246.544 254.79L246.875 254.79C253.722 247.905 264.046 238.82 277.849 227.537C291.21 216.253 301.259 207.264 307.995 200.57C314.62 193.685 319.147 186.418 321.577 178.768C324.006 171.117 322.846 163.18 318.097 154.956C312.796 145.775 305.342 138.412 295.735 132.865C286.238 127.127 276.189 124.258 265.588 124.257C255.208 124.257 248.416 127.03 245.214 132.576C241.902 137.931 243.006 145.39 248.528 154.953L183.928 154.951C174.652 138.885 170.676 124.541 172 111.918C173.546 99.2946 179.84 89.5408 190.882 82.6559C202.035 75.5798 216.887 72.0421 235.439 72.0428C254.874 72.0435 274.144 75.5825 293.248 82.6598C312.242 89.5457 329.579 99.3005 345.261 111.924C360.942 124.548 373.421 138.892 382.697 154.958C391.311 169.877 395.121 182.978 394.128 194.262C393.355 205.546 389.656 215.396 383.031 223.811C376.627 232.226 366.688 242.554 353.217 254.794L435.375 254.797L464.198 304.716L275.367 304.709L246.544 254.79Z"
|
|
||||||
fill="#F0ACB8"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M246.544 254.79L246.875 254.79C253.722 247.905 264.046 238.82 277.849 227.537C291.21 216.253 301.259 207.264 307.995 200.57C314.62 193.685 319.147 186.418 321.577 178.768C324.006 171.117 322.846 163.18 318.097 154.956C312.796 145.775 305.342 138.412 295.735 132.865C286.238 127.127 276.189 124.258 265.588 124.257C255.208 124.257 248.416 127.03 245.214 132.576C241.902 137.931 243.006 145.39 248.528 154.953L183.928 154.951C174.652 138.885 170.676 124.541 172 111.918C173.546 99.2946 179.84 89.5408 190.882 82.6559C202.035 75.5798 216.887 72.0421 235.439 72.0428C254.874 72.0435 274.144 75.5825 293.248 82.6598C312.242 89.5457 329.579 99.3005 345.261 111.924C360.942 124.548 373.421 138.892 382.697 154.958C391.311 169.877 395.121 182.978 394.128 194.262C393.355 205.546 389.656 215.396 383.031 223.811C376.627 232.226 366.688 242.554 353.217 254.794L435.375 254.797L464.198 304.716L275.367 304.709L246.544 254.79Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
:style="{ mixBlendMode: 'hard-light' }"
|
|
||||||
class="duration-750 starting:translate-y-4 starting:opacity-0 translate-y-0 opacity-100 transition-all delay-300"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M67.41 125.402L44.5515 125.401L15.5625 75.1953L101.364 75.1985L233.886 304.712L170.942 304.71L67.41 125.402Z"
|
|
||||||
fill="#F0ACB8"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M67.41 125.402L44.5515 125.401L15.5625 75.1953L101.364 75.1985L233.886 304.712L170.942 304.71L67.41 125.402Z"
|
|
||||||
stroke="#1B1B18"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
<svg
|
|
||||||
class="relative -ml-8 -mt-[4.9rem] hidden w-[448px] max-w-none dark:block lg:-mt-[6.6rem] lg:ml-0"
|
|
||||||
viewBox="0 0 440 376"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<g class="duration-750 starting:translate-y-4 starting:opacity-0 translate-y-0 opacity-100 transition-all delay-300">
|
|
||||||
<path
|
|
||||||
d="M188.263 355.73L188.595 355.73C195.441 348.845 205.766 339.761 219.569 328.477C232.93 317.193 242.978 308.205 249.714 301.511C256.34 294.626 260.867 287.358 263.296 279.708C265.725 272.058 264.565 264.121 259.816 255.896C254.516 246.716 247.062 239.352 237.454 233.805C227.957 228.067 217.908 225.198 207.307 225.198C196.927 225.197 190.136 227.97 186.934 233.516C183.621 238.872 184.726 246.331 190.247 255.894L125.647 255.891C116.371 239.825 112.395 225.481 113.72 212.858C115.265 200.235 121.559 190.481 132.602 183.596C143.754 176.52 158.607 172.982 177.159 172.983C196.594 172.984 215.863 176.523 234.968 183.6C253.961 190.486 271.299 200.241 286.98 212.864C302.661 225.488 315.14 239.833 324.416 255.899C333.03 270.817 336.841 283.918 335.847 295.203C335.075 306.487 331.376 316.336 324.75 324.751C318.346 333.167 308.408 343.494 294.936 355.734L377.094 355.737L405.917 405.656L217.087 405.649L188.263 355.73Z"
|
|
||||||
fill="black"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M9.11884 226.339L-13.7396 226.338L-42.7286 176.132L43.0733 176.135L175.595 405.649L112.651 405.647L9.11884 226.339Z"
|
|
||||||
fill="black"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M188.263 355.73L188.595 355.73C195.441 348.845 205.766 339.761 219.569 328.477C232.93 317.193 242.978 308.205 249.714 301.511C256.34 294.626 260.867 287.358 263.296 279.708C265.725 272.058 264.565 264.121 259.816 255.896C254.516 246.716 247.062 239.352 237.454 233.805C227.957 228.067 217.908 225.198 207.307 225.198C196.927 225.197 190.136 227.97 186.934 233.516C183.621 238.872 184.726 246.331 190.247 255.894L125.647 255.891C116.371 239.825 112.395 225.481 113.72 212.858C115.265 200.235 121.559 190.481 132.602 183.596C143.754 176.52 158.607 172.982 177.159 172.983C196.594 172.984 215.863 176.523 234.968 183.6C253.961 190.486 271.299 200.241 286.98 212.864C302.661 225.488 315.14 239.833 324.416 255.899C333.03 270.817 336.841 283.918 335.847 295.203C335.075 306.487 331.376 316.336 324.75 324.751C318.346 333.167 308.408 343.494 294.936 355.734L377.094 355.737L405.917 405.656L217.087 405.649L188.263 355.73Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M9.11884 226.339L-13.7396 226.338L-42.7286 176.132L43.0733 176.135L175.595 405.649L112.651 405.647L9.11884 226.339Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M204.592 327.449L204.923 327.449C211.769 320.564 222.094 311.479 235.897 300.196C249.258 288.912 259.306 279.923 266.042 273.23C272.668 266.345 277.195 259.077 279.624 251.427C282.053 243.777 280.893 235.839 276.145 227.615C270.844 218.435 263.39 211.071 253.782 205.524C244.285 199.786 234.236 196.917 223.635 196.916C213.255 196.916 206.464 199.689 203.262 205.235C199.949 210.59 201.054 218.049 206.575 227.612L141.975 227.61C132.699 211.544 128.723 197.2 130.048 184.577C131.593 171.954 137.887 162.2 148.93 155.315C160.083 148.239 174.935 144.701 193.487 144.702C212.922 144.703 232.192 148.242 251.296 155.319C270.289 162.205 287.627 171.96 303.308 184.583C318.989 197.207 331.468 211.552 340.745 227.618C349.358 242.536 353.169 255.637 352.175 266.921C351.403 278.205 347.704 288.055 341.078 296.47C334.674 304.885 324.736 315.213 311.264 327.453L393.422 327.456L422.246 377.375L233.415 377.368L204.592 327.449Z"
|
|
||||||
fill="#391800"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M25.447 198.058L2.58852 198.057L-26.4005 147.851L59.4015 147.854L191.923 377.368L128.979 377.365L25.447 198.058Z"
|
|
||||||
fill="#391800"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M204.592 327.449L204.923 327.449C211.769 320.564 222.094 311.479 235.897 300.196C249.258 288.912 259.306 279.923 266.042 273.23C272.668 266.345 277.195 259.077 279.624 251.427C282.053 243.777 280.893 235.839 276.145 227.615C270.844 218.435 263.39 211.071 253.782 205.524C244.285 199.786 234.236 196.917 223.635 196.916C213.255 196.916 206.464 199.689 203.262 205.235C199.949 210.59 201.054 218.049 206.575 227.612L141.975 227.61C132.699 211.544 128.723 197.2 130.048 184.577C131.593 171.954 137.887 162.2 148.93 155.315C160.083 148.239 174.935 144.701 193.487 144.702C212.922 144.703 232.192 148.242 251.296 155.319C270.289 162.205 287.627 171.96 303.308 184.583C318.989 197.207 331.468 211.552 340.745 227.618C349.358 242.536 353.169 255.637 352.175 266.921C351.403 278.205 347.704 288.055 341.078 296.47C334.674 304.885 324.736 315.213 311.264 327.453L393.422 327.456L422.246 377.375L233.415 377.368L204.592 327.449Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M25.447 198.058L2.58852 198.057L-26.4005 147.851L59.4015 147.854L191.923 377.368L128.979 377.365L25.447 198.058Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
class="duration-750 starting:translate-y-4 starting:opacity-0 translate-y-0 opacity-100 transition-all delay-300"
|
|
||||||
:style="{ mixBlendMode: 'hard-light' }"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M217.342 305.363L217.673 305.363C224.519 298.478 234.844 289.393 248.647 278.11C262.008 266.826 272.056 257.837 278.792 251.144C285.418 244.259 289.945 236.991 292.374 229.341C294.803 221.691 293.643 213.753 288.895 205.529C283.594 196.349 276.14 188.985 266.532 183.438C257.035 177.7 246.986 174.831 236.385 174.83C226.005 174.83 219.214 177.603 216.012 183.149C212.699 188.504 213.804 195.963 219.325 205.527L154.725 205.524C145.449 189.458 141.473 175.114 142.798 162.491C144.343 149.868 150.637 140.114 161.68 133.229C172.833 126.153 187.685 122.615 206.237 122.616C225.672 122.617 244.942 126.156 264.046 133.233C283.039 140.119 300.377 149.874 316.058 162.497C331.739 175.121 344.218 189.466 353.495 205.532C362.108 220.45 365.919 233.551 364.925 244.835C364.153 256.12 360.454 265.969 353.828 274.384C347.424 282.799 337.486 293.127 324.014 305.367L406.172 305.37L434.996 355.289L246.165 355.282L217.342 305.363Z"
|
|
||||||
fill="#733000"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M38.197 175.972L15.3385 175.971L-13.6505 125.765L72.1515 125.768L204.673 355.282L141.729 355.279L38.197 175.972Z"
|
|
||||||
fill="#733000"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M217.342 305.363L217.673 305.363C224.519 298.478 234.844 289.393 248.647 278.11C262.008 266.826 272.056 257.837 278.792 251.144C285.418 244.259 289.945 236.991 292.374 229.341C294.803 221.691 293.643 213.753 288.895 205.529C283.594 196.349 276.14 188.985 266.532 183.438C257.035 177.7 246.986 174.831 236.385 174.83C226.005 174.83 219.214 177.603 216.012 183.149C212.699 188.504 213.804 195.963 219.325 205.527L154.725 205.524C145.449 189.458 141.473 175.114 142.798 162.491C144.343 149.868 150.637 140.114 161.68 133.229C172.833 126.153 187.685 122.615 206.237 122.616C225.672 122.617 244.942 126.156 264.046 133.233C283.039 140.119 300.377 149.874 316.058 162.497C331.739 175.121 344.218 189.466 353.495 205.532C362.108 220.45 365.919 233.551 364.925 244.835C364.153 256.12 360.454 265.969 353.828 274.384C347.424 282.799 337.486 293.127 324.014 305.367L406.172 305.37L434.996 355.289L246.165 355.282L217.342 305.363Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M38.197 175.972L15.3385 175.971L-13.6505 125.765L72.1515 125.768L204.673 355.282L141.729 355.279L38.197 175.972Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
<g class="duration-750 starting:translate-y-4 starting:opacity-0 translate-y-0 opacity-100 transition-all delay-300">
|
|
||||||
<path
|
|
||||||
d="M217.342 305.363L217.673 305.363C224.519 298.478 234.844 289.393 248.647 278.11C262.008 266.826 272.056 257.837 278.792 251.144C285.418 244.259 289.945 236.991 292.374 229.341C294.803 221.691 293.643 213.753 288.895 205.529C283.594 196.349 276.14 188.985 266.532 183.438C257.035 177.7 246.986 174.831 236.385 174.83C226.005 174.83 219.214 177.603 216.012 183.149C212.699 188.504 213.804 195.963 219.325 205.527L154.726 205.524C145.449 189.458 141.473 175.114 142.798 162.491C144.343 149.868 150.637 140.114 161.68 133.229C172.833 126.153 187.685 122.615 206.237 122.616C225.672 122.617 244.942 126.156 264.046 133.233C283.039 140.119 300.377 149.874 316.058 162.497C331.739 175.121 344.218 189.466 353.495 205.532C362.108 220.45 365.919 233.551 364.925 244.835C364.153 256.12 360.454 265.969 353.828 274.384C347.424 282.799 337.486 293.127 324.014 305.367L406.172 305.37L434.996 355.289L246.165 355.282L217.342 305.363Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M38.197 175.972L15.3385 175.971L-13.6505 125.765L72.1515 125.768L204.673 355.282L141.729 355.279L38.197 175.972Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
<g class="duration-750 starting:translate-y-4 starting:opacity-0 translate-y-0 opacity-100 transition-all delay-300">
|
|
||||||
<path
|
|
||||||
d="M188.467 355.363L188.798 355.363C195.644 348.478 205.969 339.393 219.772 328.11C233.133 316.826 243.181 307.837 249.917 301.144C253.696 297.217 256.792 293.166 259.205 288.991C261.024 285.845 262.455 282.628 263.499 279.341C265.928 271.691 264.768 263.753 260.02 255.529C254.719 246.349 247.265 238.985 237.657 233.438C228.16 227.7 218.111 224.831 207.51 224.83C197.13 224.83 190.339 227.603 187.137 233.149C183.824 238.504 184.929 245.963 190.45 255.527L125.851 255.524C116.574 239.458 112.598 225.114 113.923 212.491C114.615 206.836 116.261 201.756 118.859 197.253C122.061 191.704 126.709 187.03 132.805 183.229C143.958 176.153 158.81 172.615 177.362 172.616C196.797 172.617 216.067 176.156 235.171 183.233C254.164 190.119 271.502 199.874 287.183 212.497C302.864 225.121 315.343 239.466 324.62 255.532C333.233 270.45 337.044 283.551 336.05 294.835C335.46 303.459 333.16 311.245 329.151 318.194C327.915 320.337 326.515 322.4 324.953 324.384C318.549 332.799 308.611 343.127 295.139 355.367L377.297 355.37L406.121 405.289L217.29 405.282L188.467 355.363Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M9.32197 225.972L-13.5365 225.971L-42.5255 175.765L43.2765 175.768L175.798 405.282L112.854 405.279L9.32197 225.972Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M345.247 111.915C329.566 99.2919 312.229 89.5371 293.235 82.6512L235.167 183.228C254.161 190.114 271.498 199.869 287.179 212.492L345.247 111.915Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M382.686 154.964C373.41 138.898 360.931 124.553 345.25 111.93L287.182 212.506C302.863 225.13 315.342 239.475 324.618 255.541L382.686 154.964Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M293.243 82.6472C274.139 75.57 254.869 72.031 235.434 72.0303L177.366 172.607C196.801 172.608 216.071 176.147 235.175 183.224L293.243 82.6472Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M394.118 194.257C395.112 182.973 391.301 169.872 382.688 154.953L324.619 255.53C333.233 270.448 337.044 283.55 336.05 294.834L394.118 194.257Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M235.432 72.0311C216.88 72.0304 202.027 75.5681 190.875 82.6442L132.806 183.221C143.959 176.145 158.812 172.607 177.363 172.608L235.432 72.0311Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M265.59 124.25C276.191 124.251 286.24 127.12 295.737 132.858L237.669 233.435C228.172 227.697 218.123 224.828 207.522 224.827L265.59 124.25Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M295.719 132.859C305.326 138.406 312.78 145.77 318.081 154.95L260.013 255.527C254.712 246.347 247.258 238.983 237.651 233.436L295.719 132.859Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M387.218 217.608C391.227 210.66 393.527 202.874 394.117 194.25L336.049 294.827C335.459 303.451 333.159 311.237 329.15 318.185L387.218 217.608Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M245.211 132.577C248.413 127.03 255.204 124.257 265.584 124.258L207.516 224.835C197.136 224.834 190.345 227.607 187.143 233.154L245.211 132.577Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M318.094 154.945C322.842 163.17 324.002 171.107 321.573 178.757L263.505 279.334C265.934 271.684 264.774 263.746 260.026 255.522L318.094 154.945Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M176.925 96.6737C180.127 91.1249 184.776 86.4503 190.871 82.6499L132.803 183.227C126.708 187.027 122.059 191.702 118.857 197.25L176.925 96.6737Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M387.226 217.606C385.989 219.749 384.59 221.813 383.028 223.797L324.96 324.373C326.522 322.39 327.921 320.326 329.157 318.183L387.226 217.606Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M317.269 188.408C319.087 185.262 320.519 182.045 321.562 178.758L263.494 279.335C262.451 282.622 261.019 285.839 259.201 288.985L317.269 188.408Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M245.208 132.573C241.895 137.928 243 145.387 248.522 154.95L190.454 255.527C184.932 245.964 183.827 238.505 187.14 233.15L245.208 132.573Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M176.93 96.6719C174.331 101.175 172.686 106.255 171.993 111.91L113.925 212.487C114.618 206.831 116.263 201.752 118.862 197.249L176.93 96.6719Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M317.266 188.413C314.853 192.589 311.757 196.64 307.978 200.566L249.91 301.143C253.689 297.216 256.785 293.166 259.198 288.99L317.266 188.413Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M464.198 304.708L435.375 254.789L377.307 355.366L406.13 405.285L464.198 304.708Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M353.209 254.787C366.68 242.548 376.618 232.22 383.023 223.805L324.955 324.382C318.55 332.797 308.612 343.124 295.141 355.364L353.209 254.787Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M435.37 254.787L353.212 254.784L295.144 355.361L377.302 355.364L435.37 254.787Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M183.921 154.947L248.521 154.95L190.453 255.527L125.853 255.524L183.921 154.947Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M171.992 111.914C170.668 124.537 174.643 138.881 183.92 154.947L125.852 255.524C116.575 239.458 112.599 225.114 113.924 212.491L171.992 111.914Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M307.987 200.562C301.251 207.256 291.203 216.244 277.842 227.528L219.774 328.105C233.135 316.821 243.183 307.832 249.919 301.139L307.987 200.562Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M15.5469 75.1797L44.5359 125.386L-13.5321 225.963L-42.5212 175.756L15.5469 75.1797Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M277.836 227.536C264.033 238.82 253.708 247.904 246.862 254.789L188.794 355.366C195.64 348.481 205.965 339.397 219.768 328.113L277.836 227.536Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M275.358 304.706L464.189 304.713L406.12 405.29L217.29 405.283L275.358 304.706Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M44.5279 125.39L67.3864 125.39L9.31834 225.967L-13.5401 225.966L44.5279 125.39Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M101.341 75.1911L233.863 304.705L175.795 405.282L43.2733 175.768L101.341 75.1911ZM15.5431 75.19L-42.525 175.767L43.277 175.77L101.345 75.1932L15.5431 75.19Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M246.866 254.784L246.534 254.784L188.466 355.361L188.798 355.361L246.866 254.784Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M246.539 254.781L275.362 304.701L217.294 405.277L188.471 355.358L246.539 254.781Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M67.3906 125.391L170.923 304.698L112.855 405.275L9.32257 225.967L67.3906 125.391Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M170.921 304.699L233.865 304.701L175.797 405.278L112.853 405.276L170.921 304.699Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="bevel"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
class="duration-750 starting:translate-y-4 starting:opacity-0 translate-y-0 opacity-100 transition-all delay-300"
|
|
||||||
:style="{ mixBlendMode: 'hard-light' }"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M246.544 254.79L246.875 254.79C253.722 247.905 264.046 238.82 277.849 227.537C291.21 216.253 301.259 207.264 307.995 200.57C314.62 193.685 319.147 186.418 321.577 178.768C324.006 171.117 322.846 163.18 318.097 154.956C312.796 145.775 305.342 138.412 295.735 132.865C286.238 127.127 276.189 124.258 265.588 124.257C255.208 124.257 248.416 127.03 245.214 132.576C241.902 137.931 243.006 145.39 248.528 154.953L183.928 154.951C174.652 138.885 170.676 124.541 172 111.918C173.546 99.2946 179.84 89.5408 190.882 82.6559C202.035 75.5798 216.887 72.0421 235.439 72.0428C254.874 72.0435 274.144 75.5825 293.248 82.6598C312.242 89.5457 329.579 99.3005 345.261 111.924C360.942 124.548 373.421 138.892 382.697 154.958C391.311 169.877 395.121 182.978 394.128 194.262C393.355 205.546 389.656 215.396 383.031 223.811C376.627 232.226 366.688 242.554 353.217 254.794L435.375 254.797L464.198 304.716L275.367 304.709L246.544 254.79Z"
|
|
||||||
fill="#4B0600"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M246.544 254.79L246.875 254.79C253.722 247.905 264.046 238.82 277.849 227.537C291.21 216.253 301.259 207.264 307.995 200.57C314.62 193.685 319.147 186.418 321.577 178.768C324.006 171.117 322.846 163.18 318.097 154.956C312.796 145.775 305.342 138.412 295.735 132.865C286.238 127.127 276.189 124.258 265.588 124.257C255.208 124.257 248.416 127.03 245.214 132.576C241.902 137.931 243.006 145.39 248.528 154.953L183.928 154.951C174.652 138.885 170.676 124.541 172 111.918C173.546 99.2946 179.84 89.5408 190.882 82.6559C202.035 75.5798 216.887 72.0421 235.439 72.0428C254.874 72.0435 274.144 75.5825 293.248 82.6598C312.242 89.5457 329.579 99.3005 345.261 111.924C360.942 124.548 373.421 138.892 382.697 154.958C391.311 169.877 395.121 182.978 394.128 194.262C393.355 205.546 389.656 215.396 383.031 223.811C376.627 232.226 366.688 242.554 353.217 254.794L435.375 254.797L464.198 304.716L275.367 304.709L246.544 254.79Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
class="duration-750 starting:translate-y-4 starting:opacity-0 translate-y-0 opacity-100 transition-all delay-300"
|
|
||||||
:style="{ mixBlendMode: 'hard-light' }"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M67.41 125.402L44.5515 125.401L15.5625 75.1953L101.364 75.1985L233.886 304.712L170.942 304.71L67.41 125.402Z"
|
|
||||||
fill="#4B0600"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M67.41 125.402L44.5515 125.401L15.5625 75.1953L101.364 75.1985L233.886 304.712L170.942 304.71L67.41 125.402Z"
|
|
||||||
stroke="#FF750F"
|
|
||||||
stroke-width="1"
|
|
||||||
/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
<div
|
<div
|
||||||
class="absolute inset-0 rounded-t-lg shadow-[inset_0px_0px_0px_1px_rgba(26,26,0,0.16)] dark:shadow-[inset_0px_0px_0px_1px_#fffaed2d] lg:overflow-hidden lg:rounded-r-lg lg:rounded-t-none"
|
class="flex justify-center items-center absolute inset-0 rounded-t-lg shadow-[inset_0px_0px_0px_1px_rgba(26,26,0,0.16)] dark:shadow-[inset_0px_0px_0px_1px_#fffaed2d] lg:overflow-hidden lg:rounded-r-lg lg:rounded-t-none"
|
||||||
/>
|
>
|
||||||
|
|
||||||
|
<PageLogo />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,7 +8,7 @@ use App\Http\Controllers\PageRender;
|
|||||||
|
|
||||||
Route::get('/', function () {
|
Route::get('/', function () {
|
||||||
return Inertia::render('Welcome');
|
return Inertia::render('Welcome');
|
||||||
})->name('home');
|
})->name('forsiden');
|
||||||
|
|
||||||
Route::get('/p/{slug}', [PageRender::class, 'view'])->name('page.view');
|
Route::get('/p/{slug}', [PageRender::class, 'view'])->name('page.view');
|
||||||
|
|
||||||
|