aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/card-v4.svelte7
-rw-r--r--src/components/locale-switcher.svelte14
-rw-r--r--src/i18n/en/index.ts2
-rw-r--r--src/i18n/i18n-types.ts16
-rw-r--r--src/i18n/nb/index.ts2
-rw-r--r--src/lib/sanity/client.ts (renamed from src/lib/sanity-client.ts)0
-rw-r--r--src/lib/sanity/locales.ts5
-rw-r--r--src/lib/sanity/schemas/default/contact.ts36
-rw-r--r--src/lib/sanity/schemas/default/description.ts22
-rw-r--r--src/lib/sanity/schemas/default/faq.ts22
-rw-r--r--src/lib/sanity/schemas/default/hero.ts28
-rw-r--r--src/lib/sanity/schemas/default/index.ts16
-rw-r--r--src/lib/sanity/schemas/default/product.ts37
-rw-r--r--src/lib/sanity/types/block-array.ts9
-rw-r--r--src/lib/utils.ts12
-rw-r--r--src/routes/[lang=lang]/+page.server.ts39
-rw-r--r--src/routes/[lang=lang]/+page.svelte43
-rw-r--r--src/routes/[lang=lang]/sections/contact.svelte4
-rw-r--r--src/routes/[lang=lang]/sections/description.svelte6
-rw-r--r--src/routes/[lang=lang]/sections/hero.svelte61
-rw-r--r--src/routes/[lang=lang]/sections/products.svelte15
-rw-r--r--src/routes/parts/header.svelte11
22 files changed, 298 insertions, 109 deletions
diff --git a/src/components/card-v4.svelte b/src/components/card-v4.svelte
index ff35492..fccd423 100644
--- a/src/components/card-v4.svelte
+++ b/src/components/card-v4.svelte
@@ -16,16 +16,13 @@
<PortableText value={description} />
{/if}
</p>
- <div class="flex flex-wrap gap-3">
- <a href="#0" class="btn btn--subtle">Learn more</a>
- <a href="#0" class="btn btn--primary">Buy</a>
- </div>
+ <slot />
</div>
</div>
<style lang="postcss">
.card {
- @apply flex flex-col bg-floor rounded-xl overflow-hidden;
+ @apply flex flex-col bg-floor rounded-xl overflow-hidden h-max;
box-shadow: 0 0 0 1px hsla(230, 13%, 9%, 0.05), 0 0.3px 0.4px hsla(230, 13%, 9%, 0.02),
0 0.9px 1.5px hsla(230, 13%, 9%, 0.045), 0 3.5px 6px hsla(230, 13%, 9%, 0.09);
}
diff --git a/src/components/locale-switcher.svelte b/src/components/locale-switcher.svelte
index 938d18a..aa4e0c4 100644
--- a/src/components/locale-switcher.svelte
+++ b/src/components/locale-switcher.svelte
@@ -35,12 +35,8 @@
<svelte:window on:popstate={handlePopStateEvent} />
-<ul>
- {#each locales as l}
- <li>
- <a class:active={l === $locale} href={`${replaceLocaleInUrl($page.url, l)}`}>
- {l}
- </a>
- </li>
- {/each}
-</ul>
+{#if $locale == "en"}
+ <a href={replaceLocaleInUrl($page.url, "nb")}>Norsk Bokmål</a>
+{:else if $locale == "nb"}
+ <a href={replaceLocaleInUrl($page.url, "en")}>English</a>
+{/if}
diff --git a/src/i18n/en/index.ts b/src/i18n/en/index.ts
index a6b79c2..1f8260f 100644
--- a/src/i18n/en/index.ts
+++ b/src/i18n/en/index.ts
@@ -7,6 +7,8 @@ const en = {
emailTitle: "Email",
phoneTitle: "Phone",
},
+ goToBookingPage: "Go to booking",
+ ourServices: "Our services",
homeTitle: "Home",
} satisfies BaseTranslation;
diff --git a/src/i18n/i18n-types.ts b/src/i18n/i18n-types.ts
index 9a32b2f..52b1fd2 100644
--- a/src/i18n/i18n-types.ts
+++ b/src/i18n/i18n-types.ts
@@ -33,6 +33,14 @@ type RootTranslation = {
phoneTitle: string
}
/**
+ * G​o​ ​t​o​ ​b​o​o​k​i​n​g
+ */
+ goToBookingPage: string
+ /**
+ * O​u​r​ ​s​e​r​v​i​c​e​s
+ */
+ ourServices: string
+ /**
* H​o​m​e
*/
homeTitle: string
@@ -58,6 +66,14 @@ export type TranslationFunctions = {
phoneTitle: () => LocalizedString
}
/**
+ * Go to booking
+ */
+ goToBookingPage: () => LocalizedString
+ /**
+ * Our services
+ */
+ ourServices: () => LocalizedString
+ /**
* Home
*/
homeTitle: () => LocalizedString
diff --git a/src/i18n/nb/index.ts b/src/i18n/nb/index.ts
index 5206b07..0064639 100644
--- a/src/i18n/nb/index.ts
+++ b/src/i18n/nb/index.ts
@@ -7,6 +7,8 @@ const nb = {
emailTitle: "E-postadresse",
phoneTitle: "Telefon",
},
+ goToBookingPage: "Gå til bestilling",
+ ourServices: "Våre tjenester",
homeTitle: "Hjem",
} satisfies Translation;
diff --git a/src/lib/sanity-client.ts b/src/lib/sanity/client.ts
index 7aa868b..7aa868b 100644
--- a/src/lib/sanity-client.ts
+++ b/src/lib/sanity/client.ts
diff --git a/src/lib/sanity/locales.ts b/src/lib/sanity/locales.ts
new file mode 100644
index 0000000..c3280f4
--- /dev/null
+++ b/src/lib/sanity/locales.ts
@@ -0,0 +1,5 @@
+export const supportedLanguages = [
+ { id: "en", title: "English" },
+ { id: "nb", title: "Norsk Bokmål", isDefault: true },
+];
+export const baseLanguage = supportedLanguages.find((l) => l.isDefault) as { id: string; title: string, isDefault: boolean };
diff --git a/src/lib/sanity/schemas/default/contact.ts b/src/lib/sanity/schemas/default/contact.ts
new file mode 100644
index 0000000..03b1942
--- /dev/null
+++ b/src/lib/sanity/schemas/default/contact.ts
@@ -0,0 +1,36 @@
+import { s } from "sanity-typed-schema-builder";
+
+export default s.document({
+ name: "contact",
+ title: "Contact section",
+ // @ts-ignore
+ i18n: true,
+ fields: [
+ {
+ title: "Address lines",
+ name: "addressLines",
+ type: s.array({
+ of: [s.string()]
+ }),
+ optional: true
+ },
+ {
+ title: "Email",
+ name: "email",
+ type: s.string(),
+ optional: true,
+ },
+ {
+ title: "Phone",
+ name: "phone",
+ type: s.string(),
+ optional: true,
+ },
+ {
+ title: "Phone hours",
+ name: "phoneHours",
+ type: s.string(),
+ optional: true,
+ }
+ ],
+}); \ No newline at end of file
diff --git a/src/lib/sanity/schemas/default/description.ts b/src/lib/sanity/schemas/default/description.ts
new file mode 100644
index 0000000..3c5cbfa
--- /dev/null
+++ b/src/lib/sanity/schemas/default/description.ts
@@ -0,0 +1,22 @@
+import { s } from "sanity-typed-schema-builder";
+
+export default s.document({
+ name: "description",
+ // @ts-ignore
+ i18n: true,
+ title: "Description section",
+ fields: [
+ {
+ title: "Title",
+ name: "title",
+ type: s.string(),
+ },
+ {
+ title: "Content",
+ name: "content",
+ type: s.array({
+ of: [s.block()]
+ })
+ },
+ ],
+});
diff --git a/src/lib/sanity/schemas/default/faq.ts b/src/lib/sanity/schemas/default/faq.ts
new file mode 100644
index 0000000..6fb9e71
--- /dev/null
+++ b/src/lib/sanity/schemas/default/faq.ts
@@ -0,0 +1,22 @@
+import { s } from "sanity-typed-schema-builder";
+
+export default s.document({
+ name: "faq",
+ title: "FAQ section",
+ // @ts-ignore
+ i18n: true,
+ fields: [
+ {
+ name: "title",
+ title: "Question",
+ type: s.string(),
+ },
+ {
+ name: "answer",
+ title: "Answer",
+ type: s.array({
+ of: [s.block()]
+ }),
+ }
+ ]
+}) \ No newline at end of file
diff --git a/src/lib/sanity/schemas/default/hero.ts b/src/lib/sanity/schemas/default/hero.ts
new file mode 100644
index 0000000..df7b8ae
--- /dev/null
+++ b/src/lib/sanity/schemas/default/hero.ts
@@ -0,0 +1,28 @@
+import { s } from "sanity-typed-schema-builder";
+
+export default s.document({
+ name: "hero",
+ title: "Hero section",
+ // @ts-ignore
+ i18n: true,
+ fields: [
+ {
+ title: "Title",
+ name: "title",
+ type: s.string(),
+ },
+ {
+ title: "Content",
+ name: "content",
+ type: s.array({
+ of: [s.block()]
+ }),
+ },
+ {
+ title: "Image",
+ name: "image",
+ type: s.image(),
+ optional: true
+ },
+ ],
+});
diff --git a/src/lib/sanity/schemas/default/index.ts b/src/lib/sanity/schemas/default/index.ts
new file mode 100644
index 0000000..4befb4d
--- /dev/null
+++ b/src/lib/sanity/schemas/default/index.ts
@@ -0,0 +1,16 @@
+import contact from "./contact";
+import description from "./description";
+import faq from "./faq";
+import hero from "./hero";
+import product from "./product";
+
+export default {
+ name: "default-schema",
+ types: [
+ contact.schema(),
+ product.schema(),
+ description.schema(),
+ faq.schema(),
+ hero.schema()
+ ]
+} \ No newline at end of file
diff --git a/src/lib/sanity/schemas/default/product.ts b/src/lib/sanity/schemas/default/product.ts
new file mode 100644
index 0000000..92db714
--- /dev/null
+++ b/src/lib/sanity/schemas/default/product.ts
@@ -0,0 +1,37 @@
+import { s } from "sanity-typed-schema-builder";
+
+export default s.document({
+ name: "product",
+ title: "Products",
+ // @ts-ignore
+ i18n: true,
+ fields: [
+ {
+ name: "title",
+ title: "Title",
+ type: s.string(),
+ },
+ {
+ name: "duration",
+ title: "Duration",
+ type: s.string()
+ },
+ {
+ name: "cost",
+ title: "Cost",
+ type: s.string()
+ },
+ {
+ name: "description",
+ title: "Description",
+ type: s.array({
+ of: [s.block()]
+ })
+ },
+ {
+ name: "orderLink",
+ title: "Link to booking",
+ type: s.url()
+ },
+ ],
+}); \ No newline at end of file
diff --git a/src/lib/sanity/types/block-array.ts b/src/lib/sanity/types/block-array.ts
new file mode 100644
index 0000000..28ca0c4
--- /dev/null
+++ b/src/lib/sanity/types/block-array.ts
@@ -0,0 +1,9 @@
+export type SanityBlockArray = {
+ _type: string;
+ children: any[];
+ markDefs?: any[] | undefined;
+ style?: string | undefined;
+ listItem?: string | undefined;
+ level?: number | undefined;
+ _key: string;
+}[] \ No newline at end of file
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index f7c040d..1dc98f0 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -14,14 +14,4 @@ export const replaceLocaleInUrl = (url: URL, locale: string, full = false): stri
const newUrl = new URL(url.toString());
newUrl.pathname = new_pathname;
return newUrl.toString();
-};
-
-export function fromLocalizedString(localizedString: string | object, locale: Locales) {
- if (typeof localizedString === "string") return localizedString;
- // @ts-ignore
- if (localizedString[locale]) return localizedString[locale];
- // @ts-ignore
- if (localizedString["nb"]) return localizedString["nb"];
- // @ts-ignore
- if (localizedString["en"]) return localizedString["en"];
-}
+}; \ No newline at end of file
diff --git a/src/routes/[lang=lang]/+page.server.ts b/src/routes/[lang=lang]/+page.server.ts
index c2284ee..deafae3 100644
--- a/src/routes/[lang=lang]/+page.server.ts
+++ b/src/routes/[lang=lang]/+page.server.ts
@@ -1,22 +1,31 @@
-import { sanity } from "$lib/sanity-client";
+import { sanity } from "$lib/sanity/client";
import type { PageServerLoad } from "./$types";
import groq from "groq";
import type { ContactModel } from "./sections/contact.svelte";
-import { fromLocalizedString } from "$lib/utils";
import type { HeroModel } from "./sections/hero.svelte";
import type { DescriptionModel } from "./sections/description.svelte";
+import type { s } from "sanity-typed-schema-builder";
+import type contactType from "$lib/sanity/schemas/default/contact";
+import type heroType from "$lib/sanity/schemas/default/hero";
+import type descriptionType from "$lib/sanity/schemas/default/description";
+import type productType from "$lib/sanity/schemas/default/product";
+import type { ProductsModel } from "./sections/products.svelte";
export const load = (async ({ locals }) => {
- const contactSection = await sanity.fetch(groq`*[_type == "contact"][0]`);
- const heroSection = await sanity.fetch(groq`*[_type == "hero"][0]`);
- const descriptionSection = await sanity.fetch(groq`*[_type == "description"][0]`);
- const products = await sanity.fetch(groq`*[_type == "product"]`);
+ const commonParams = {
+ lang: locals.locale
+ }
+ const contactSection: s.infer<typeof contactType> = await sanity.fetch(groq`*[_type == "contact" && __i18n_lang == $lang][0]`, { ...commonParams }) ?? {};
+ const heroSection: s.infer<typeof heroType> = await sanity.fetch(groq`*[_type == "hero" && __i18n_lang == $lang][0]`, { ...commonParams }) ?? {};
+ const descriptionSection: s.infer<typeof descriptionType> = await sanity.fetch(groq`*[_type == "description" && __i18n_lang == $lang][0]`, { ...commonParams }) ?? {};
+ const products: Array<s.infer<typeof productType>> = await sanity.fetch(groq`*[_type == "product" && __i18n_lang == $lang]`, { ...commonParams }) ?? [];
+
return {
contact: {
- phone: fromLocalizedString(contactSection.phone, locals.locale),
- email: fromLocalizedString(contactSection.email, locals.locale),
- phoneHours: fromLocalizedString(contactSection.phoneHours, locals.locale),
- addressLines: contactSection.addressLines.map((el: string | object) => fromLocalizedString(el, locals.locale)),
+ phone: contactSection.phone,
+ email: contactSection.email,
+ phoneHours: contactSection.phoneHours,
+ addressLines: contactSection.addressLines?.map((el: string | object) => el) ?? [],
} as ContactModel,
hero: {
title: heroSection.title,
@@ -26,6 +35,14 @@ export const load = (async ({ locals }) => {
title: descriptionSection.title,
content: descriptionSection.content,
} as DescriptionModel,
- products: products
+ products: {
+ products: products.map((p) => ({
+ cost: p.cost,
+ description: p.description,
+ duration: p.duration,
+ orderLink: p.orderLink,
+ title: p.title
+ }))
+ } as ProductsModel
};
}) satisfies PageServerLoad;
diff --git a/src/routes/[lang=lang]/+page.svelte b/src/routes/[lang=lang]/+page.svelte
index f2028c6..0ab63ee 100644
--- a/src/routes/[lang=lang]/+page.svelte
+++ b/src/routes/[lang=lang]/+page.svelte
@@ -3,13 +3,48 @@
import Hero from "./sections/hero.svelte";
import Description from "./sections/description.svelte";
import Products from "./sections/products.svelte";
+ import LL from "$i18n/i18n-svelte";
import type { PageData } from "./$types";
export let data: PageData;
</script>
-<Hero model={data.hero} />
-<Description model={data.description} />
-<Contact model={data.contact} />
-<Products model={data.products} />
+<main>
+ <section id="hero">
+ <div class="hero">
+ <Hero model={data.hero} />
+ </div>
+ <div>
+ <Description model={data.description} />
+ </div>
+ </section>
+ <section>
+ <h3 class="mb-3">{$LL.ourServices()}</h3>
+ <Products model={data.products} />
+ </section>
+ <section>
+ <Contact model={data.contact} />
+ </section>
+</main>
+
+<style>
+ main {
+ margin: 0 5vw 2vh 5vw;
+ display: flex;
+ flex-direction: column;
+ }
+ main section {
+ margin-bottom: 2vh;
+ }
+
+ #hero {
+ display: grid;
+ grid-template-columns: repeat(2, 50%);
+ justify-content: space-between;
+ }
+
+ #hero .hero {
+ padding: 3.2vw;
+ }
+</style>
diff --git a/src/routes/[lang=lang]/sections/contact.svelte b/src/routes/[lang=lang]/sections/contact.svelte
index b058180..2898e83 100644
--- a/src/routes/[lang=lang]/sections/contact.svelte
+++ b/src/routes/[lang=lang]/sections/contact.svelte
@@ -23,9 +23,9 @@
{#if visible}
<section class="contact relative z-1">
- <div class="w-[calc(100%_-_2.5rem)] lg:w-[calc(100%_-_4rem)] mx-auto max-w-7xl">
+ <div class="mx-auto">
<div class="mb-8 lg:mb-12">
- <h1 class="text-center">{$LL.contact.title()}</h1>
+ <h3>{$LL.contact.title()}</h3>
</div>
<div class="grid grid-cols-12 gap-8 lg:gap-12">
diff --git a/src/routes/[lang=lang]/sections/description.svelte b/src/routes/[lang=lang]/sections/description.svelte
index 79a3939..1fc23ab 100644
--- a/src/routes/[lang=lang]/sections/description.svelte
+++ b/src/routes/[lang=lang]/sections/description.svelte
@@ -1,7 +1,9 @@
<script context="module" lang="ts">
+ import type { SanityBlockArray } from "$lib/sanity/types/block-array";
+
export type DescriptionModel = {
title: string;
- content?: any;
+ content?: SanityBlockArray;
};
</script>
@@ -19,7 +21,7 @@
</script>
{#if visible}
- <h3>{model.title}</h3>
+ <h3 class="mb-3">{model.title}</h3>
{#if model.content}
<PortableText value={model.content} />
{/if}
diff --git a/src/routes/[lang=lang]/sections/hero.svelte b/src/routes/[lang=lang]/sections/hero.svelte
index 3cdf221..8a874dc 100644
--- a/src/routes/[lang=lang]/sections/hero.svelte
+++ b/src/routes/[lang=lang]/sections/hero.svelte
@@ -1,7 +1,9 @@
<script context="module" lang="ts">
+ import type { SanityBlockArray } from "$lib/sanity/types/block-array";
+
export type HeroModel = {
title: string;
- content?: any;
+ content?: SanityBlockArray;
};
</script>
@@ -19,57 +21,8 @@
</script>
{#if visible}
- <section class="has-section-divider-bottom bg-contrast-low/50">
- <div class="py-20 lg:py-32">
- <div class="w-[calc(100%_-_2.5rem)] lg:w-[calc(100%_-_4rem)] mx-auto max-w-lg md:max-w-3xl">
- <div class="text-component">
- <h1>{model.title}</h1>
- {#if model.content}
- <PortableText value={model.content} />
- {/if}
- </div>
- </div>
- </div>
-
- <div class="section-divider">
- <svg viewBox="0 0 1920 60" aria-hidden="true">
- <path
- class="fill-floor"
- d="M-153.5,85.5a4002.033,4002.033,0,0,1,658-71c262.854-6.5,431.675,15.372,600,27,257.356,17.779,624.828,19.31,1089-58v102Z"
- />
- </svg>
- </div>
- </section>
+ <h1>{model.title}</h1>
+ {#if model.content}
+ <PortableText value={model.content} />
+ {/if}
{/if}
-
-<style lang="postcss">
- :root {
- --section-divider-width: 1920;
- --section-divider-height: 60;
- --section-divider-ratio: calc(100% * var(--section-divider-height) / var(--section-divider-width));
- }
-
- [class*="has-section-divider"] {
- position: relative;
- }
-
- .has-section-divider-bottom {
- padding-bottom: var(--section-divider-ratio);
- }
-
- .section-divider {
- position: absolute;
- bottom: -1px;
- left: 0;
- width: 100%;
- overflow: hidden;
- }
- .section-divider svg {
- position: relative;
- display: block;
- height: auto;
- max-width: none;
- width: 102%;
- left: -1%;
- }
-</style>
diff --git a/src/routes/[lang=lang]/sections/products.svelte b/src/routes/[lang=lang]/sections/products.svelte
index 816e276..a2999dc 100644
--- a/src/routes/[lang=lang]/sections/products.svelte
+++ b/src/routes/[lang=lang]/sections/products.svelte
@@ -1,4 +1,5 @@
<script context="module" lang="ts">
+ import type { SanityBlockArray } from "$lib/sanity/types/block-array";
export type ProductsModel = {
products: ProductModel[];
};
@@ -7,13 +8,14 @@
title: string;
duration: string;
cost: string;
- description: string;
+ description: SanityBlockArray;
orderLink: string;
};
</script>
<script lang="ts">
import CardV4 from "$components/card-v4.svelte";
+ import LL from "$i18n/i18n-svelte";
export let model: ProductsModel;
@@ -28,14 +30,19 @@
{#if visible}
<div class="wrapper">
{#each model.products as product}
- <CardV4 description={product.description} title={product.title} />
+ <CardV4 description={product.description} title={product.title}>
+ <div class="flex flex-wrap justify-end align-bottom">
+ <a href={product.orderLink} class="btn btn--primary">{$LL.goToBookingPage()}</a>
+ </div>
+ </CardV4>
{/each}
</div>
{/if}
<style lang="postcss">
.wrapper {
- display: grid;
- grid-template-columns: repeat(50%);
+ display: flex;
+ flex-direction: row;
+ gap: 1em
}
</style>
diff --git a/src/routes/parts/header.svelte b/src/routes/parts/header.svelte
index 55f1da0..4be4b21 100644
--- a/src/routes/parts/header.svelte
+++ b/src/routes/parts/header.svelte
@@ -1,12 +1,9 @@
<script lang="ts">
- import { locale } from "$i18n/i18n-svelte";
import LocaleSwitcher from "$components/locale-switcher.svelte";
</script>
-<header>
- <a href="/{$locale}">
- <h1>Auroraklinikken</h1>
- </a>
-
- <LocaleSwitcher />
+<header class="flex">
+ <div class="flex justify-end">
+ <LocaleSwitcher />
+ </div>
</header>