diff --git a/components.198185.json b/components.198185.json index a69c258f..47671801 100644 --- a/components.198185.json +++ b/components.198185.json @@ -2247,31 +2247,40 @@ "name": "landing-page", "display_name": null, "created_at": "2024-01-09T16:40:58.537Z", - "updated_at": "2024-01-16T10:35:21.911Z", + "updated_at": "2024-02-29T15:42:02.200Z", "id": 5142044, "schema": { + "keep_top_bar_hidden": { + "type": "boolean", + "pos": 0, + "required": false + }, "blocks": { "type": "bloks", "restrict_type": "groups", "restrict_components": true, "component_whitelist": [], - "component_group_whitelist": ["c9011224-9690-43bd-b686-e8f60ef6c7f6"] + "component_group_whitelist": ["c9011224-9690-43bd-b686-e8f60ef6c7f6"], + "pos": 1 }, "tab-577daf7c-b61e-4a23-8184-bd9c01ae0af3": { "display_name": "SEO", "keys": ["seo_title", "seo_description", "seo_og_image", "change_frequency", "priority"], - "pos": 0, + "pos": 2, "type": "tab" }, "seo_title": { - "type": "text" + "type": "text", + "pos": 3 }, "seo_description": { - "type": "text" + "type": "text", + "pos": 4 }, "seo_og_image": { "type": "asset", - "filetypes": ["images"] + "filetypes": ["images"], + "pos": 5 }, "change_frequency": { "type": "option", @@ -2313,12 +2322,14 @@ "value": "never", "name": "Never" } - ] + ], + "pos": 6 }, "priority": { "type": "number", "description": "The priority of the page relative to other pages on your site, where 0.1 is the lowest priority and 1.0 is the highest priority.\n\n1.0-0.8\nHomepage, product information, landing pages.\n\n0.7-0.4\nNews articles, some weather services, blog posts, pages that no site would be complete without.\n\n0.3-0.0\nFAQs, outdated info, old press releases, completely static pages that are still relevant enough to keep from deleting entirely.", - "decimals": 1 + "decimals": 1, + "pos": 7 } }, "image": null, diff --git a/src/components/blocks/estimation.svelte b/src/components/blocks/estimation.svelte index fd7783f6..818b5541 100644 --- a/src/components/blocks/estimation.svelte +++ b/src/components/blocks/estimation.svelte @@ -2,50 +2,58 @@ import type { EstimationStoryblok } from '$types/bloks'; import IllustrationEmply from '../illustrations/assets/illustration-emply.webp'; import IllustrationEmplyLight from '../illustrations/assets/illustration-emply-light.webp'; - import ArrowLight from '../illustrations/assets/arrow-estimations-white.webp'; - import ArrowDark from '../illustrations/assets/arrow-estimations.webp'; import { theme } from '$lib/stores/theme'; - import { Icon, MultiSelect } from '@significa/svelte-ui'; + import { CheckboxGroup, Radio } from '@significa/svelte-ui'; import clsx from 'clsx'; import ContactForm from '$components/contact-form.svelte'; - import { estimations } from '$lib/estimations'; - import type { ListboxOption } from '@melt-ui/svelte/dist/builders/listbox/types'; + import { estimations, estimationsCheckbox } from '$lib/estimations'; + import HandAsset from '../illustrations/assets/hand.webp'; - import PreFooterAsset from '../illustrations/assets/pre-footer.webp'; - import PreFooterAssetLight from '../illustrations/assets/pre-footer-light.webp'; + import { t } from '$lib/i18n'; export let block: EstimationStoryblok; let open = false; - $: src = $theme === 'dark' ? IllustrationEmply : IllustrationEmplyLight; - $: srcArrow = $theme === 'dark' ? ArrowDark : ArrowLight; - let selected: Record[]> = {}; + let selectedRadio: Array = []; + let selectedCheckbox: Array = []; - $: selectedMap = Object.entries(selected).map(([key, value]) => ({ key, value })); + $: selectedValuesToNotion = [ + ...estimations.flatMap((estimation, index) => + estimation.options + .filter((option) => option.name === selectedRadio[index]) + .map((option) => `${estimation.name} / ${option.name}`) + ), + ...estimationsCheckbox.flatMap((estimation) => + estimation.options + .filter((option) => selectedCheckbox.includes(option.name)) + .map((option) => `${estimation.name} / ${option.name}`) + ) + ].join(' , '); - $: selectedKeyValues = selectedMap.map(({ value }) => value.map((v) => v.value)).flat(); + $: estimationsMapRadio = estimations + .map((v, i) => v.options.filter((o) => o.name === selectedRadio[i])) + .flat(); - let estimationsMap = estimations.map((v) => v.options.filter((o) => o.name)).flat(); + $: estimationsMapCheckbox = estimationsCheckbox + .map((v) => v.options.filter((v) => selectedCheckbox.includes(v.name))) + .flat(); - $: combinedBudgetPower = estimationsMap - .filter((r) => selectedKeyValues.includes(r.name)) - .reduce( - (a, b) => { - return { - lowBudget: a.lowBudget + Number(b['low-bud-point']), - highBudget: a.highBudget + Number(b['high-bud-point']), - lowPower: a.lowPower + Number(b['low-est-point']), - highPower: a.highPower + Number(b['high-est-point']) - }; - }, - { lowBudget: 0, highBudget: 0, lowPower: 0, highPower: 0 } - ); + $: combinedBudgetPower = [...estimationsMapRadio, ...estimationsMapCheckbox].reduce( + (a, b) => { + return { + lowBudget: a.lowBudget + Number(b['low-est-point']) * 14500, + highBudget: a.highBudget + Number(b['high-est-point']) * 14500, + lowPower: a.lowPower + Number(b['low-est-point']), + highPower: a.highPower + Number(b['high-est-point']) + }; + }, + { lowBudget: 0, highBudget: 0, lowPower: 0, highPower: 0 } + ); - // open / close form - $: Object.values(combinedBudgetPower).every((val) => val !== 0) ? (open = true) : (open = false); + $: open = Object.values(combinedBudgetPower).every((val) => val !== 0);
@@ -58,92 +66,130 @@
-
+
-
-
-
-
+
+
+

{block.title}

{block.description}

-
- - {#each estimations as { name, options }} - o.name)} - bind:selected={selected[name]} - selectedLabel={name} - icon="plus" - class="w-full xs:w-fit" - /> - {/each} -
- -
- {#each selectedMap as option} - {#each option.value as op} +
+
+
+
+ {#each estimations as options, i} +
+
+

+ {options.name} +

+ +
+
+ {#each options.options as opt} + + {/each} +
+
+ {/each} + {#each estimationsCheckbox as options}
- {op.label} - +

+ {options.name} +

+ + {#each options.options as opt} + + {/each}
{/each} - {/each} +
-
-

{t('estimation.man.power')}

-

- {combinedBudgetPower.lowPower === 0 - ? '-' - : combinedBudgetPower.lowPower + ` to ` + combinedBudgetPower.highPower} -

-

{t('estimation.total')}

-

- {combinedBudgetPower.lowBudget === 0 - ? '-' - : combinedBudgetPower.lowBudget + `€ to ` + combinedBudgetPower.highBudget + `€`} -

+
+
+
+

+ {t('estimation.man.power')} +

+

+ {combinedBudgetPower.lowPower === 0 + ? '-' + : combinedBudgetPower.lowPower + ` to ` + combinedBudgetPower.highPower} +

+
+
+

+ {t('estimation.total')} +

+

+ {combinedBudgetPower.lowBudget === 0 + ? '-' + : combinedBudgetPower.lowBudget + + `€ to ` + + combinedBudgetPower.highBudget + + `€`} +

+
+
- +
-
+ diff --git a/src/components/blocks/work-recognitions.svelte b/src/components/blocks/work-recognitions.svelte index 57caf1ec..b339da2d 100644 --- a/src/components/blocks/work-recognitions.svelte +++ b/src/components/blocks/work-recognitions.svelte @@ -33,7 +33,7 @@
diff --git a/src/components/top-navigation.svelte b/src/components/top-navigation.svelte index c6948402..db234a95 100644 --- a/src/components/top-navigation.svelte +++ b/src/components/top-navigation.svelte @@ -19,6 +19,8 @@ }); const scrollStatus = createTopNavScrollStatus(); + + $: isNavHidden = $page.data?.page?.story?.content?.keep_top_bar_hidden;
@@ -28,7 +30,7 @@ !$scrollStatus.isPastZero ? 'border-b-transparent' : 'border-b-border', !$scrollStatus.isPastThreshold ? 'translate-y-0' - : $scrollStatus.direction === 'down' + : $scrollStatus.direction === 'down' || isNavHidden ? '-translate-y-full' : 'translate-y-0' )} diff --git a/src/lib/estimations.ts b/src/lib/estimations.ts index 3c904348..6584e91b 100644 --- a/src/lib/estimations.ts +++ b/src/lib/estimations.ts @@ -1,27 +1,84 @@ export const estimations = [ { - name: 'Strategy', + name: 'Website', options: [ { - name: 'UX Research', + name: 'Design', 'low-est-point': '1', - 'high-est-point': '2', - 'low-bud-point': '10000', - 'high-bud-point': '20000' + 'high-est-point': '2' }, { - name: 'MVP build', + name: 'Design and dev.', + 'low-est-point': '2', + 'high-est-point': '4' + } + ] + }, + { + name: 'E-commerce', + options: [ + { + name: 'Design', + 'low-est-point': '2', + 'high-est-point': '3' + }, + { + name: 'Design and dev.', + 'low-est-point': '5', + 'high-est-point': '8' + } + ] + }, + { + name: 'Web app', + options: [ + { + name: 'Design', 'low-est-point': '1', - 'high-est-point': '2', - 'low-bud-point': '10000', - 'high-bud-point': '20000' + 'high-est-point': '3' }, { - name: 'Website', + name: 'Design and dev.', + 'low-est-point': '3', + 'high-est-point': '6' + } + ] + }, + { + name: 'Mobile app', + options: [ + { + name: 'Design', 'low-est-point': '1', - 'high-est-point': '2', - 'low-bud-point': '10000', - 'high-bud-point': '20000' + 'high-est-point': '3' + }, + { + name: 'Design and dev.', + 'low-est-point': '3', + 'high-est-point': '6' + } + ] + } +]; + +export const estimationsCheckbox = [ + { + name: 'Others (design and dev.)', + options: [ + { + name: 'TV App', + 'low-est-point': '2', + 'high-est-point': '5' + }, + { + name: 'Desktop App', + 'low-est-point': '3', + 'high-est-point': '6' + }, + { + name: 'Watch App', + 'low-est-point': '2', + 'high-est-point': '4' } ] } diff --git a/src/lib/i18n/data.json b/src/lib/i18n/data.json index 1c4a1240..68da7659 100644 --- a/src/lib/i18n/data.json +++ b/src/lib/i18n/data.json @@ -171,5 +171,6 @@ "proposals.package.reply.manpower.title": "What is estimated manpower?", "proposals.package.reply.manpower.desc": "Manpower refers to the total capacity available for the project.", "handbook.last.updated": "Last updated", - "handbook.navigation.website": "Significa website" + "handbook.navigation.website": "Significa website", + "estimate.clear": "Clear" } diff --git a/src/lib/i18n/types.ts b/src/lib/i18n/types.ts index 987dca7c..ed609894 100644 --- a/src/lib/i18n/types.ts +++ b/src/lib/i18n/types.ts @@ -171,7 +171,8 @@ export const TranslationKeys = [ 'proposals.package.reply.manpower.title', 'proposals.package.reply.manpower.desc', 'handbook.last.updated', - 'handbook.navigation.website' + 'handbook.navigation.website', + 'estimate.clear' ] as const; export type TranslationKey = (typeof TranslationKeys)[number]; diff --git a/src/types/bloks.d.ts b/src/types/bloks.d.ts index 18779e7f..80a5a715 100644 --- a/src/types/bloks.d.ts +++ b/src/types/bloks.d.ts @@ -6,6 +6,7 @@ export type MultilinkStoryblok = cached_url?: string; anchor?: string; linktype?: 'story'; + target?: '_self' | '_blank'; story?: { name: string; created_at?: string; @@ -42,11 +43,13 @@ export type MultilinkStoryblok = cached_url?: string; anchor?: string; linktype?: 'asset' | 'url'; + target?: '_self' | '_blank'; [k: string]: any; } | { email?: string; linktype?: 'email'; + target?: '_self' | '_blank'; [k: string]: any; }; @@ -88,13 +91,20 @@ export interface AboutPageStoryblok { } export interface AssetStoryblok { - alt?: string; - copyright?: string; + _uid?: string; id: number; - filename: string; + alt?: string; name: string; - title?: string; focus?: string; + source?: string; + title?: string; + filename: string; + copyright?: string; + fieldtype?: string; + meta_data?: null | { + [k: string]: any; + }; + is_external_url?: boolean; [k: string]: any; } @@ -589,6 +599,7 @@ export interface ImageGridStoryblok { } export interface LandingPageStoryblok { + keep_top_bar_hidden?: boolean; blocks?: ( | ClientsStoryblok | CtaCardStoryblok