feat: useLayoutWrapper
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
fragment LayoutColored on GroupLayoutColored_Fields {
|
||||
color
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
fragment LayoutContained on GroupLayoutContained_Fields {
|
||||
container
|
||||
verticalPadding
|
||||
bgColor
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { LayoutContainedFragment } from "#graphql/operations";
|
||||
import { tv, type VariantProps } from "tailwind-variants";
|
||||
|
||||
const props = defineProps<LayoutContainedFragment>();
|
||||
|
||||
const layoutWrapperVariants = tv({
|
||||
slots: {
|
||||
base: "",
|
||||
inner: "",
|
||||
},
|
||||
variants: {
|
||||
container: {
|
||||
default: { inner: "container" },
|
||||
lg: { inner: "container-lg" },
|
||||
xl: { inner: "container-xl" },
|
||||
fluid: { inner: "container-fluid" },
|
||||
none: { inner: "container-none" },
|
||||
},
|
||||
verticalPadding: {
|
||||
sm: { base: "py-3" },
|
||||
md: { base: "py-6" },
|
||||
lg: { base: "py-12" },
|
||||
},
|
||||
bgColor: {
|
||||
default: { base: "bg-default" },
|
||||
muted: { base: "bg-muted" },
|
||||
inverted: { base: "bg-inverted text-inverted" },
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
container: "default",
|
||||
verticalPadding: "md",
|
||||
bgColor: "default",
|
||||
},
|
||||
});
|
||||
const { base, inner } = layoutWrapperVariants({
|
||||
container: props.container[0],
|
||||
verticalPadding: props.verticalPadding[0],
|
||||
bgColor: props.bgColor[0],
|
||||
} as VariantProps<typeof layoutWrapperVariants>);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section :class="base()">
|
||||
<div :class="inner()">
|
||||
<slot />
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,3 @@
|
||||
fragment LayoutPadded on GroupLayoutPadded_Fields {
|
||||
verticalPadding
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{ layoutSettings?: LayoutSettings }>();
|
||||
const { base, inner } = useLayoutWrapper(props.layoutSettings);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section :class="base()">
|
||||
<div :class="inner()">
|
||||
<slot />
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -6,9 +6,7 @@ defineProps<NodePageFragment>();
|
||||
|
||||
<template>
|
||||
<div id="node-page">
|
||||
<h1 v-if="!isFrontPage" class="text-4xl font-bold">
|
||||
{{ title }}
|
||||
</h1>
|
||||
<PageHeader v-if="!isFrontPage" :title="title"></PageHeader>
|
||||
<BuilderSections :sections="groupPostPage?.sections || []" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
title?: string;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header v-if="title" class="bg-accented py-6">
|
||||
<div class="container">
|
||||
<h1 class="heading-1">
|
||||
{{ title }}
|
||||
</h1>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
@@ -1,18 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
const { isLoggedIn } = useAuth();
|
||||
const { isRedirecting } = useAuthConnexion();
|
||||
const layoutSettings: LayoutWrapperProps = {
|
||||
container: "lg",
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section data-section-name="auth-connexion" class="py-12">
|
||||
<div class="container-sm">
|
||||
<AuthState>
|
||||
<AuthRedirecting v-if="isRedirecting" />
|
||||
<template v-else>
|
||||
<AuthLogoutForm v-if="isLoggedIn" />
|
||||
<AuthLoginForm v-else />
|
||||
</template>
|
||||
</AuthState>
|
||||
</div>
|
||||
</section>
|
||||
<LayoutWrapper data-section-name="auth-connexion" :layout-settings="layoutSettings">
|
||||
<AuthState>
|
||||
<AuthRedirecting v-if="isRedirecting" />
|
||||
<template v-else>
|
||||
<AuthLogoutForm v-if="isLoggedIn" />
|
||||
<AuthLoginForm v-else />
|
||||
</template>
|
||||
</AuthState>
|
||||
</LayoutWrapper>
|
||||
</template>
|
||||
|
||||
@@ -2,4 +2,8 @@ fragment SectionHeroSplit on GroupAbstractBuilderSectionsHeroSplitLayout {
|
||||
content
|
||||
reverse
|
||||
...AcfMedia
|
||||
layoutSettings {
|
||||
...LayoutColored
|
||||
...LayoutPadded
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ import { tv, type VariantProps } from "tailwind-variants";
|
||||
import type { SectionHeroSplitFragment } from "#graphql/operations";
|
||||
|
||||
const tvSectionHeroSplit = tv({
|
||||
extend: tvLayoutWrapper,
|
||||
slots: {
|
||||
base: "py-6",
|
||||
container: "container flex flex-col items-center gap-6",
|
||||
content: "flex-1",
|
||||
media: "w-full basis-1/2",
|
||||
@@ -27,6 +27,7 @@ const tvSectionHeroSplit = tv({
|
||||
const props = defineProps<SectionHeroSplitFragment>();
|
||||
const classes = tvSectionHeroSplit({
|
||||
reverse: props.reverse,
|
||||
...props.layoutSettings,
|
||||
} as VariantProps<typeof tvSectionHeroSplit>);
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
fragment SectionTextBlock on GroupAbstractBuilderSectionsTextBlockLayout {
|
||||
content
|
||||
layoutSettings {
|
||||
...LayoutColored
|
||||
...LayoutContained
|
||||
...LayoutPadded
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ defineProps<SectionTextBlockFragment>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<LayoutContained data-section-type="text-block" v-bind="layoutSettings!">
|
||||
<LayoutWrapper data-section-type="text-block" :layout-settings="layoutSettings">
|
||||
<UiProse :content="content" />
|
||||
</LayoutContained>
|
||||
</LayoutWrapper>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { tv, type VariantProps } from "tailwind-variants";
|
||||
import * as z from "zod";
|
||||
|
||||
// Tailwind Variants for LayoutWrapper
|
||||
export const tvLayoutWrapper = tv({
|
||||
slots: {
|
||||
base: "",
|
||||
inner: "",
|
||||
},
|
||||
variants: {
|
||||
// LayoutColored
|
||||
color: {
|
||||
default: { base: "bg-default" },
|
||||
muted: { base: "bg-muted" },
|
||||
elevated: { base: "bg-elevated" },
|
||||
accented: { base: "bg-accented" },
|
||||
inverted: { base: "bg-inverted text-inverted" },
|
||||
primary: { base: "bg-primary text-inverted" },
|
||||
},
|
||||
// LayoutContained
|
||||
container: {
|
||||
default: { inner: "container" },
|
||||
xl: { inner: "container-xl" },
|
||||
lg: { inner: "container-lg" },
|
||||
fluid: { inner: "container-fluid" },
|
||||
fullbleed: { inner: "container-fullbleed" },
|
||||
},
|
||||
// LayoutPadded
|
||||
verticalPadding: {
|
||||
sm: { base: "py-3" },
|
||||
md: { base: "py-6" },
|
||||
lg: { base: "py-12" },
|
||||
none: {},
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
color: "default",
|
||||
container: "default",
|
||||
verticalPadding: "md",
|
||||
},
|
||||
});
|
||||
|
||||
export type LayoutWrapperProps = VariantProps<typeof tvLayoutWrapper>;
|
||||
|
||||
// Zod schemas for validating layout settings
|
||||
const colorEnum = z.enum(["default", "muted", "elevated", "accented", "inverted", "primary"]);
|
||||
const containerEnum = z.enum(["default", "xl", "lg", "fluid", "fullbleed"]);
|
||||
const verticalPaddingEnum = z.enum(["sm", "md", "lg", "none"]);
|
||||
|
||||
const layoutSettingsSchema = z.object({
|
||||
color: z.string().pipe(colorEnum).optional(),
|
||||
container: z.string().pipe(containerEnum).optional(),
|
||||
verticalPadding: z.string().pipe(verticalPaddingEnum).optional(),
|
||||
});
|
||||
|
||||
export type LayoutSettings = z.input<typeof layoutSettingsSchema>;
|
||||
|
||||
export function useLayoutWrapper(input?: LayoutSettings) {
|
||||
try {
|
||||
return tvLayoutWrapper(layoutSettingsSchema.parse(input));
|
||||
} catch {
|
||||
return tvLayoutWrapper();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user