From 485afa2d7eabdc6c3b6012887a49894d1e9307ec Mon Sep 17 00:00:00 2001 From: Julieta Frade Date: Fri, 22 Sep 2023 11:00:51 +0100 Subject: [PATCH 1/5] feat: add scope table --- components.198185.json | 15 +- src/lib/i18n/data.json | 13 +- src/lib/i18n/types.ts | 13 +- src/lib/utils/proposalTables.ts | 20 +++ .../proposal/[slug]/+page.server.ts | 3 +- .../(proposals)/proposal/[slug]/hero.svelte | 2 +- .../[slug]/proposal-navigation.svelte | 2 +- .../proposal/[slug]/proposal-page.svelte | 40 +++-- .../proposal/[slug]/proposal-scope.svelte | 152 ++++++++++++++++++ src/types/bloks.d.ts | 2 +- 10 files changed, 235 insertions(+), 27 deletions(-) create mode 100644 src/lib/utils/proposalTables.ts create mode 100644 src/routes/(proposals)/proposal/[slug]/proposal-scope.svelte diff --git a/components.198185.json b/components.198185.json index 32a6aab7..0cb3e162 100644 --- a/components.198185.json +++ b/components.198185.json @@ -2526,7 +2526,7 @@ "name": "proposal-department", "display_name": null, "created_at": "2023-09-11T15:40:29.996Z", - "updated_at": "2023-09-11T15:40:38.569Z", + "updated_at": "2023-09-21T09:46:47.753Z", "id": 4555221, "schema": { "title": { @@ -2539,9 +2539,9 @@ }, "image": null, "preview_field": null, - "is_root": false, + "is_root": true, "preview_tmpl": null, - "is_nestable": true, + "is_nestable": false, "all_presets": [ { "id": 1897410, @@ -2845,7 +2845,7 @@ "name": "proposal-team-entry", "display_name": null, "created_at": "2023-09-11T15:39:52.162Z", - "updated_at": "2023-09-13T16:08:55.251Z", + "updated_at": "2023-09-21T09:47:12.652Z", "id": 4555220, "schema": { "team_member": { @@ -2855,7 +2855,7 @@ "options": [] }, "department": { - "type": "bloks", + "type": "option", "restrict_type": "", "restrict_components": true, "component_whitelist": ["proposal-department"], @@ -2863,7 +2863,10 @@ "maximum": 1, "required": true, "pos": 1, - "key": "department" + "key": "department", + "use_uuid": true, + "source": "internal_stories", + "filter_content_type": ["proposal-department"] }, "role": { "type": "bloks", diff --git a/src/lib/i18n/data.json b/src/lib/i18n/data.json index 7858f3b0..688264fd 100644 --- a/src/lib/i18n/data.json +++ b/src/lib/i18n/data.json @@ -102,5 +102,16 @@ "proposals.hero.client": "Client", "proposals.hero.createdby": "Created by", "proposals.hero.date": "Date", - "proposals.nav.versions": "Versions" + "proposals.nav.versions": "Versions", + "proposals.scope.delivarable": "Delivarable", + "proposals.scope.service": "service", + "proposals.scope.multiple-features": "Multiple Features", + "proposals.show": "Show", + "proposals.hide": "Hide", + "proposals.team.department": "Department", + "proposals.team.team-member": "Team Member", + "proposals.team.role": "Role", + "proposals.team.rate": "Rate", + "proposals.included": "Included", + "proposals.scope.features": "Features" } diff --git a/src/lib/i18n/types.ts b/src/lib/i18n/types.ts index d51e4003..c825dd0a 100644 --- a/src/lib/i18n/types.ts +++ b/src/lib/i18n/types.ts @@ -102,7 +102,18 @@ export const TranslationKeys = [ 'proposals.hero.client', 'proposals.hero.createdby', 'proposals.hero.date', - 'proposals.nav.versions' + 'proposals.nav.versions', + 'proposals.scope.delivarable', + 'proposals.scope.service', + 'proposals.scope.multiple-features', + 'proposals.show', + 'proposals.hide', + 'proposals.team.department', + 'proposals.team.team-member', + 'proposals.team.role', + 'proposals.team.rate', + 'proposals.included', + 'proposals.scope.features' ] as const; export type TranslationKey = (typeof TranslationKeys)[number]; diff --git a/src/lib/utils/proposalTables.ts b/src/lib/utils/proposalTables.ts new file mode 100644 index 00000000..f5ec51f8 --- /dev/null +++ b/src/lib/utils/proposalTables.ts @@ -0,0 +1,20 @@ +export function getColumnsWidthClassName(col: 'first' | 'central' | 'last') { + switch (col) { + case 'first': + return 'lg:w-[calc(var(--container-margin)+var(--section-title-width)+theme(padding.container))]'; + case 'central': + return 'lg:w-[--central-cols-width]'; + case 'last': + return 'lg:w-[calc(var(--container-margin)+var(--last-col-content-width)+theme(padding.container))]'; + default: + break; + } +} + +export function getContainersPaddingClassName(side: 'pl' | 'pr') { + return side + '-[calc(theme(padding.container)+var(--container-margin))]'; +} + +export function getHeaderCellTextClassName(side: 'left' | 'right') { + return 'text-xs uppercase tracking-wider text-foreground-secondary text-' + side; +} diff --git a/src/routes/(proposals)/proposal/[slug]/+page.server.ts b/src/routes/(proposals)/proposal/[slug]/+page.server.ts index 3f4bc62e..fbc14321 100644 --- a/src/routes/(proposals)/proposal/[slug]/+page.server.ts +++ b/src/routes/(proposals)/proposal/[slug]/+page.server.ts @@ -31,7 +31,8 @@ export const load = async ({ cookies, fetch, params, url }) => { try { res = await storyblok.get('cdn/stories/' + url.pathname, { - version + version, + resolve_relations: ['proposal-team-entry.department'] }); } catch (error) { if (isStatusError(error) && error.status === 404) { diff --git a/src/routes/(proposals)/proposal/[slug]/hero.svelte b/src/routes/(proposals)/proposal/[slug]/hero.svelte index 12846cf8..a50e1ff0 100644 --- a/src/routes/(proposals)/proposal/[slug]/hero.svelte +++ b/src/routes/(proposals)/proposal/[slug]/hero.svelte @@ -8,7 +8,7 @@ export let date: string | undefined; -
+

{proposal.title}

{proposal.description}

diff --git a/src/routes/(proposals)/proposal/[slug]/proposal-navigation.svelte b/src/routes/(proposals)/proposal/[slug]/proposal-navigation.svelte index 1650e34e..54e1be0e 100644 --- a/src/routes/(proposals)/proposal/[slug]/proposal-navigation.svelte +++ b/src/routes/(proposals)/proposal/[slug]/proposal-navigation.svelte @@ -111,7 +111,7 @@
{#if versions.length > 1} -
+

{t('proposals.nav.versions')}

diff --git a/src/routes/(proposals)/proposal/[slug]/proposal-page.svelte b/src/routes/(proposals)/proposal/[slug]/proposal-page.svelte index 2151ff4a..1d501a85 100644 --- a/src/routes/(proposals)/proposal/[slug]/proposal-page.svelte +++ b/src/routes/(proposals)/proposal/[slug]/proposal-page.svelte @@ -4,6 +4,7 @@ import Hero from './hero.svelte'; import ProposalNavigation from './proposal-navigation.svelte'; import RichText from '$components/rich-text.svelte'; + import ProposalScope from './proposal-scope.svelte'; export let proposal: ProposalStoryblok; const versions = proposal?.versions || []; @@ -11,34 +12,43 @@ $: content = versions.find((v) => v.version_name === version); $: sections = (content?.body || []).map((b) => b.title || '').filter(Boolean); + + let sectionTitleWidth; + let containerWidth: number; + let windowWidth: number; + + $: containerMargin = (windowWidth - containerWidth) / 2; +
+
+ version.version_name)} bind:version /> -
+
{#each content?.body || [] as section} -
-
-

{section.title}

- +
+
+

{section.title}.

- - {#if section.data === 'scope' && content?.scope} - - {:else if section.data === 'team' && content?.estimates} - - {:else if section.data === 'estimates' && content?.estimates} - - {:else if section.data === 'timeline' && content?.estimates} - - {/if} +
+ {#if section.data === 'scope' && content?.scope} + + {:else if section.data === 'team' && content?.team} + + {:else if section.data === 'estimates' && content?.estimates} + + {:else if section.data === 'timeline' && content?.estimates} + + {/if} +
{/each}
diff --git a/src/routes/(proposals)/proposal/[slug]/proposal-scope.svelte b/src/routes/(proposals)/proposal/[slug]/proposal-scope.svelte new file mode 100644 index 00000000..f03aeed9 --- /dev/null +++ b/src/routes/(proposals)/proposal/[slug]/proposal-scope.svelte @@ -0,0 +1,152 @@ + + +
+ + + + + + + + + + + + + + + {#each data as entry, i} + {@const features = entry.features?.split('\n').filter(Boolean) || []} + + + + + + + + + + + {/each} + +

+ {t('proposals.scope.delivarable')} +

+ {t('proposals.scope.service')} +

+ {t('proposals.scope.features')} +

+

+ {entry.title}. +

+

+ {entry.description} +

+ +
+
+ {#each entry.services || [] as service} + + {/each} +
+
+

+ {t('proposals.scope.multiple-features')} +

+ {#if isShowingFeatures[i]} +
+ {#each features as feature} +

+ {feature} +

+ {/each} +
+ {/if} +
+
diff --git a/src/types/bloks.d.ts b/src/types/bloks.d.ts index ca4a613d..b101a310 100644 --- a/src/types/bloks.d.ts +++ b/src/types/bloks.d.ts @@ -705,7 +705,7 @@ export interface ProposalSectionStoryblok { } export interface ProposalTeamEntryStoryblok { - department: ProposalDepartmentStoryblok[]; + department: StoryblokStory | string; role: ProposalRoleStoryblok[]; rate_type?: '' | 'value' | 'percentage' | 'free'; rate_value?: string; From 602901ae4f174950ed35267673a77f0b4d87ded4 Mon Sep 17 00:00:00 2001 From: Julieta Frade Date: Thu, 28 Sep 2023 17:38:23 +0100 Subject: [PATCH 2/5] fix: paddings and widths --- src/lib/i18n/data.json | 20 ++++++++++- src/lib/i18n/types.ts | 20 ++++++++++- src/lib/utils/currency.ts | 4 +++ src/lib/utils/proposalTables.ts | 34 ++++++++++++++++--- .../proposal/[slug]/proposal-scope.svelte | 24 ++++++------- 5 files changed, 83 insertions(+), 19 deletions(-) create mode 100644 src/lib/utils/currency.ts diff --git a/src/lib/i18n/data.json b/src/lib/i18n/data.json index 688264fd..43f2c886 100644 --- a/src/lib/i18n/data.json +++ b/src/lib/i18n/data.json @@ -113,5 +113,23 @@ "proposals.team.role": "Role", "proposals.team.rate": "Rate", "proposals.included": "Included", - "proposals.scope.features": "Features" + "proposals.scope.features": "Features", + "proposals.estimates.area": "Area", + "proposals.estimates.phases": "Phases", + "proposals.estimates.team": "Team", + "proposals.estimates.duration": "Duration", + "proposals.estimates.predicted-cost": "Predicted Cost", + "proposals.estimates.phase": "Phase", + "proposals.estimates.people": "People", + "proposals.estimates.person": "Person", + "proposals.estimates.subtotal": "Subtotal", + "proposals.estimates.discount": "Discount", + "proposals.estimates.gran-total": "Gran Total", + "proposals.reply.description": "Ready to start a wonderful product journey with us?", + "proposals.testimonials": "Testimonials", + "proposals.testimonials.description": "How it feels to work with Significa team.", + "proposals.clients.description": "Some clients we work with", + "proposals.awards": "Awards", + "proposals.awards.description": "Celebrating great work achievements.", + "proposals.projects": "Projects" } diff --git a/src/lib/i18n/types.ts b/src/lib/i18n/types.ts index c825dd0a..44beb7bd 100644 --- a/src/lib/i18n/types.ts +++ b/src/lib/i18n/types.ts @@ -113,7 +113,25 @@ export const TranslationKeys = [ 'proposals.team.role', 'proposals.team.rate', 'proposals.included', - 'proposals.scope.features' + 'proposals.scope.features', + 'proposals.estimates.area', + 'proposals.estimates.phases', + 'proposals.estimates.team', + 'proposals.estimates.duration', + 'proposals.estimates.predicted-cost', + 'proposals.estimates.phase', + 'proposals.estimates.people', + 'proposals.estimates.person', + 'proposals.estimates.subtotal', + 'proposals.estimates.discount', + 'proposals.estimates.gran-total', + 'proposals.reply.description', + 'proposals.testimonials', + 'proposals.testimonials.description', + 'proposals.clients.description', + 'proposals.awards', + 'proposals.awards.description', + 'proposals.projects' ] as const; export type TranslationKey = (typeof TranslationKeys)[number]; diff --git a/src/lib/utils/currency.ts b/src/lib/utils/currency.ts new file mode 100644 index 00000000..7f875138 --- /dev/null +++ b/src/lib/utils/currency.ts @@ -0,0 +1,4 @@ +export const formatter = new Intl.NumberFormat('pt-PT', { + style: 'currency', + currency: 'EUR' +}); diff --git a/src/lib/utils/proposalTables.ts b/src/lib/utils/proposalTables.ts index f5ec51f8..ff186d10 100644 --- a/src/lib/utils/proposalTables.ts +++ b/src/lib/utils/proposalTables.ts @@ -1,20 +1,44 @@ -export function getColumnsWidthClassName(col: 'first' | 'central' | 'last') { +export function getColumnsWidthClassName( + col: 'first' | 'central' | 'last' | 'sticky' | 'last-empty' +) { switch (col) { case 'first': - return 'lg:w-[calc(var(--container-margin)+var(--section-title-width)+theme(padding.container))]'; + return 'lg:w-[calc(var(--container-margin)+var(--section-title-width)+theme(padding.container)+3rem)]'; case 'central': return 'lg:w-[--central-cols-width]'; case 'last': return 'lg:w-[calc(var(--container-margin)+var(--last-col-content-width)+theme(padding.container))]'; + case 'sticky': + return 'w-[--sticky-col-content-width]'; + case 'last-empty': + return 'lg:w-[calc(var(--container-margin)+theme(padding.container))]'; default: break; } } -export function getContainersPaddingClassName(side: 'pl' | 'pr') { - return side + '-[calc(theme(padding.container)+var(--container-margin))]'; +export function getContainersPaddingClassName(side: 'left' | 'right') { + switch (side) { + case 'left': + return 'pl-[calc(theme(padding.container)+var(--container-margin))]'; + case 'right': + return 'pr-[calc(theme(padding.container)+var(--container-margin))]'; + default: + break; + } } export function getHeaderCellTextClassName(side: 'left' | 'right') { - return 'text-xs uppercase tracking-wider text-foreground-secondary text-' + side; + switch (side) { + case 'left': + return 'text-xs uppercase tracking-wider text-foreground-secondary text-left'; + case 'right': + return 'text-xs uppercase tracking-wider text-foreground-secondary text-right'; + default: + break; + } +} + +export function getStickyColClassName() { + return 'right-0 sticky md:relative bg-background md:bg-transparent drop-shadow-md md:drop-shadow-none'; } diff --git a/src/routes/(proposals)/proposal/[slug]/proposal-scope.svelte b/src/routes/(proposals)/proposal/[slug]/proposal-scope.svelte index f03aeed9..f43ea6bb 100644 --- a/src/routes/(proposals)/proposal/[slug]/proposal-scope.svelte +++ b/src/routes/(proposals)/proposal/[slug]/proposal-scope.svelte @@ -29,7 +29,7 @@ style="--container-margin: {containerMargin}px; --section-title-width: {sectionTitleWidth}px; --central-cols-width: {centralColsWidth}px; - --last-col-content-width: 100px;" + --last-col-content-width: 75px;" > @@ -37,9 +37,9 @@ -

{t('proposals.scope.features')} @@ -66,7 +66,7 @@

- -

@@ -47,7 +47,7 @@

{t('proposals.scope.service')}

- +

{entry.title}.

@@ -98,7 +98,7 @@
+
{#each entry.services || [] as service} @@ -106,7 +106,7 @@
+

+ + {/if} + diff --git a/src/components/clients.svelte b/src/components/clients.svelte new file mode 100644 index 00000000..125cebd9 --- /dev/null +++ b/src/components/clients.svelte @@ -0,0 +1,21 @@ + + +
+ {#each clients as client} + {#if client.light_mode?.filename && $theme === 'light'} + {@const { src, alt, width, height } = getImageAttributes(client.light_mode)} + + {/if} + + {#if client.dark_mode?.filename && $theme === 'dark'} + {@const { src, alt, width, height } = getImageAttributes(client.dark_mode)} + + {/if} + {/each} +
diff --git a/src/components/pages/services.svelte b/src/components/pages/services.svelte index aa4378ea..a4ae9fa3 100644 --- a/src/components/pages/services.svelte +++ b/src/components/pages/services.svelte @@ -1,5 +1,4 @@ @@ -70,40 +70,14 @@ }} class="container mx-auto flex flex-col justify-between px-container py-5 lg:flex-row" > -
-
- {#if award.image?.filename} - {@const { alt, src, width, height } = getImageAttributes(award.image, { - size: [120, 0] - })} - - {/if} -
-

- {award.label} -

-

{award.name}

-
-
-
-

{award.project}

-
-
-
- {#if href} -
- -
- {/if} -
+ {/each} @@ -205,19 +179,7 @@

{data.clients_title}

{#if data.clients} -
- {#each data.clients as client} - {#if client.light_mode?.filename && $theme === 'light'} - {@const { src, alt, width, height } = getImageAttributes(client.light_mode)} - - {/if} - - {#if client.dark_mode?.filename && $theme === 'dark'} - {@const { src, alt, width, height } = getImageAttributes(client.dark_mode)} - - {/if} - {/each} -
+ {/if}
diff --git a/src/components/testimonials.svelte b/src/components/testimonials.svelte index 525bf773..0e3ff84f 100644 --- a/src/components/testimonials.svelte +++ b/src/components/testimonials.svelte @@ -20,6 +20,7 @@ export let ctaLink: MultilinkStoryblok | undefined = undefined; export let ctaLabel: string | undefined = undefined; export let testimonials: RichtextTestimonialStoryblok[] | undefined = undefined; + export let hasBorder: boolean | undefined = true; let scroll: number; let testimonialsSection: HTMLElement; @@ -31,7 +32,7 @@ -
+
Date: Thu, 28 Sep 2023 17:44:15 +0100 Subject: [PATCH 5/5] feat: add footer components --- .../proposal/[slug]/+page.server.ts | 29 +++++++++- .../(proposals)/proposal/[slug]/+page.svelte | 4 +- .../proposal/[slug]/proposal-awards.svelte | 53 +++++++++++++++++++ .../proposal/[slug]/proposal-clients.svelte | 15 ++++++ .../proposal/[slug]/proposal-projects.svelte | 21 ++++++++ .../[slug]/proposal-reply-block.svelte | 17 ++++++ .../[slug]/proposal-testimonials.svelte | 19 +++++++ 7 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 src/routes/(proposals)/proposal/[slug]/proposal-awards.svelte create mode 100644 src/routes/(proposals)/proposal/[slug]/proposal-clients.svelte create mode 100644 src/routes/(proposals)/proposal/[slug]/proposal-projects.svelte create mode 100644 src/routes/(proposals)/proposal/[slug]/proposal-reply-block.svelte create mode 100644 src/routes/(proposals)/proposal/[slug]/proposal-testimonials.svelte diff --git a/src/routes/(proposals)/proposal/[slug]/+page.server.ts b/src/routes/(proposals)/proposal/[slug]/+page.server.ts index fbc14321..22ceb139 100644 --- a/src/routes/(proposals)/proposal/[slug]/+page.server.ts +++ b/src/routes/(proposals)/proposal/[slug]/+page.server.ts @@ -1,6 +1,7 @@ import { STORYBLOK_PROPOSALS_TOKEN } from '$env/static/private'; import { PREVIEW_COOKIE_KEY } from '$lib/constants'; import { getStoryblok } from '$lib/storyblok'; +import { fetchPage } from '$lib/content'; import type { ProposalStoryblok } from '$types/bloks.js'; import type { ISbStoryData } from '@storyblok/js'; @@ -28,6 +29,8 @@ export const load = async ({ cookies, fetch, params, url }) => { } let res; + let services; + let home; try { res = await storyblok.get('cdn/stories/' + url.pathname, { @@ -48,7 +51,31 @@ export const load = async ({ cookies, fetch, params, url }) => { return failAuthentication(); } - return { story }; + try { + services = await fetchPage({ + slug: 'services', + version: cookies.get(PREVIEW_COOKIE_KEY) ? 'draft' : 'published', + fetch, + url + }); + } catch (err) { + console.error('Fetching services for proposals: ' + err); + throw err; + } + + try { + home = await fetchPage({ + slug: '', + version: cookies.get(PREVIEW_COOKIE_KEY) ? 'draft' : 'published', + fetch, + url + }); + } catch (err) { + console.error('Fetching home for proposals: ' + err); + throw err; + } + + return { story, services, home }; }; export const actions = { diff --git a/src/routes/(proposals)/proposal/[slug]/+page.svelte b/src/routes/(proposals)/proposal/[slug]/+page.svelte index 1823aa74..554ddac2 100644 --- a/src/routes/(proposals)/proposal/[slug]/+page.svelte +++ b/src/routes/(proposals)/proposal/[slug]/+page.svelte @@ -5,10 +5,12 @@ export let data; const proposal = data?.story?.content; + const services = data?.services?.story?.content?.page[0]; + const home = data?.home?.story.content.page[0]; {#if data?.story && proposal} - + {:else} {/if} diff --git a/src/routes/(proposals)/proposal/[slug]/proposal-awards.svelte b/src/routes/(proposals)/proposal/[slug]/proposal-awards.svelte new file mode 100644 index 00000000..311a8ca6 --- /dev/null +++ b/src/routes/(proposals)/proposal/[slug]/proposal-awards.svelte @@ -0,0 +1,53 @@ + + +
+
+
+

{t('proposals.awards')}.

+

{t('proposals.awards.description')}

+
+
+ +
+
+
+
    + {#each awards as award} + {@const { href, target, rel } = getAnchorFromCmsLink(award.link)} +
  • + + + +
  • + {/each} +
+
+
+
+
diff --git a/src/routes/(proposals)/proposal/[slug]/proposal-clients.svelte b/src/routes/(proposals)/proposal/[slug]/proposal-clients.svelte new file mode 100644 index 00000000..7cc5323c --- /dev/null +++ b/src/routes/(proposals)/proposal/[slug]/proposal-clients.svelte @@ -0,0 +1,15 @@ + + +
+

+ {t('proposals.clients.description')} +

+ + +
diff --git a/src/routes/(proposals)/proposal/[slug]/proposal-projects.svelte b/src/routes/(proposals)/proposal/[slug]/proposal-projects.svelte new file mode 100644 index 00000000..21679304 --- /dev/null +++ b/src/routes/(proposals)/proposal/[slug]/proposal-projects.svelte @@ -0,0 +1,21 @@ + + +
+
+
+

{t('proposals.projects')}.

+
+
+
+ {#each projects as project} + + {/each} +
+
diff --git a/src/routes/(proposals)/proposal/[slug]/proposal-reply-block.svelte b/src/routes/(proposals)/proposal/[slug]/proposal-reply-block.svelte new file mode 100644 index 00000000..79a8a7b4 --- /dev/null +++ b/src/routes/(proposals)/proposal/[slug]/proposal-reply-block.svelte @@ -0,0 +1,17 @@ + + +
+
+
+
+

{t('proposals.reply.description')}

+
+ + +
+ +
+
diff --git a/src/routes/(proposals)/proposal/[slug]/proposal-testimonials.svelte b/src/routes/(proposals)/proposal/[slug]/proposal-testimonials.svelte new file mode 100644 index 00000000..8c5bf50a --- /dev/null +++ b/src/routes/(proposals)/proposal/[slug]/proposal-testimonials.svelte @@ -0,0 +1,19 @@ + + +
+
+
+

{t('proposals.testimonials')}.

+

+ {t('proposals.testimonials.description')} +

+
+
+ +