Transferred and translated the frontend code from L10 to L12
linter / quality (push) Waiting to run
tests / ci (push) Waiting to run

This commit is contained in:
2025-05-05 19:01:27 +02:00
parent 98205954c3
commit e15d3ae146
96 changed files with 6398 additions and 701 deletions
@@ -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>
@@ -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>
@@ -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>
@@ -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>