diff --git a/.env.development b/.env.development new file mode 100644 index 000000000..812358268 --- /dev/null +++ b/.env.development @@ -0,0 +1 @@ +NEXT_PUBLIC_URL=http://localhost:3000 \ No newline at end of file diff --git a/.env.production b/.env.production new file mode 100644 index 000000000..01b130c6a --- /dev/null +++ b/.env.production @@ -0,0 +1 @@ +NEXT_PUBLIC_URL=https://$NEXT_PUBLIC_VERCEL_URL \ No newline at end of file diff --git a/README.md b/README.md index 0eb8ec4ef..9c78efe44 100644 --- a/README.md +++ b/README.md @@ -101,16 +101,16 @@ This project includes a customized Sanity Studio desk structure to enhance conte ## Managing Content -### Site Settings +### Company Information -The `Site Settings` menu allows you to configure global settings for your site, including brand assets, tracking codes, and default SEO settings. +The `Company Information` menu allows you to configure global settings for your site, including brand assets, tracking codes, and default SEO settings. -#### Social Media Profiles +### Social Media Profiles - **Adding Social Media Links**: Editors can manage social media links under the `Social Media Profiles` menu. This allows visitors to connect with the website on various social platforms. - **Supported Platforms**: The 9 supported platforms include Facebook, Instagram, and LinkedIn, but more can be added to `SoMePlatforms` if needed. -#### Navigation Management +### Navigation Management - **Setting the Landing Page**: The `Navigation Manager` allows editors to set the landing page for the site, which is crucial for determining the primary page visitors see upon arrival. - **Adding Menu Items**: Within the `Navigation Manager`, editors can add items to various pre-defined menus: @@ -118,7 +118,7 @@ The `Site Settings` menu allows you to configure global settings for your site, - **Footer Menu**: Add items to the footer menu, which consists of different sections. Each section can contain either social media links, custom links, text, or images (e.g., logos). - **Sidebar Menu**: Add links to the sidebar menu, which will appear on smaller screens to aid mobile navigation. -#### Pages +### Pages - **Creating Pages**: Content editors can create and manage pages under the `Pages` menu in the Sanity Studio. - **Adding Sections**: Each page can be customized with structured content that includes various predefined sections such as hero, article, testimonials, features, callToAction, grid, and callout. @@ -181,6 +181,77 @@ export default MyCustomComponent; By using fetchWithToken, you ensure that all data fetching happens securely, with the server-side API route handling the sensitive token. +### OpenGraph image customization + +As part of providing the basic metadata for the [OpenGraph Protocol](https://ogp.me), a fallback image is generated if no other is specified. Fonts and background can be customized as shown below. + +#### Custom fonts + +The following font utils file can be defined: + +> fonts must be placed in `/public/fonts` + +```tsx +import { readFile } from "fs/promises"; +import { join } from "path"; + +type Weight = 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900; +type FontStyle = "normal" | "italic"; +interface FontOptions { + data: Buffer | ArrayBuffer; + name: string; + weight?: Weight; + style?: FontStyle; + lang?: string; +} + +function readFont(filename: string) { + return readFile(join(process.cwd(), "public/fonts", filename)); +} + +export async function getFonts(): Promise { + return [ + { + data: await readFont("graphik_regular.woff"), + name: "Graphik", + weight: 400, + style: "normal", + }, + { + data: await readFont("graphik_medium.woff"), + name: "Graphik", + weight: 600, + style: "normal", + }, + { + data: await readFont("recoleta.ttf"), + name: "Recoleta", + weight: 600, + style: "normal", + }, + ]; +} +``` + +followed by a modification of the image route response: + +```tsx +(), + { + width: 1200, + height: 630, + fonts: await getFonts(), // add this line + }; +``` + +#### Custom background + +Simply use the CSS background property on the root element with a base64-encoded data url + +```css +background: url("data:image/png;base64,..."); +``` + ### Troubleshooting - Sanity Preview: While the Sanity preview functionality is not fully optimized, it currently meets the essential requirements. diff --git a/public/arrow-right.svg b/public/arrow-right.svg new file mode 100644 index 000000000..01d388b6c --- /dev/null +++ b/public/arrow-right.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/public/sharedStudioIcon.png b/public/sharedStudioIcon.png new file mode 100644 index 000000000..29d1d513a Binary files /dev/null and b/public/sharedStudioIcon.png differ diff --git a/public/studioIcon.png b/public/studioIcon.png new file mode 100644 index 000000000..cbec85929 Binary files /dev/null and b/public/studioIcon.png differ diff --git a/sanity.config.ts b/sanity.config.ts new file mode 100644 index 000000000..6c498f6b4 --- /dev/null +++ b/sanity.config.ts @@ -0,0 +1,11 @@ +/** + * This configuration is used to for the Sanity Studio that’s mounted on the routes: + * - `/app/studio/[[...index]]/page.tsx` + * - `/app/studioShared/[[...index]]/page.tsx` + */ + +import { defineConfig } from "sanity"; +import sharedStudioConfig from "./studioShared/studioConfig"; +import studioConfig from "./studio/studioConfig"; + +export default defineConfig([studioConfig, sharedStudioConfig]); diff --git a/src/app/(main)/[slug]/page.tsx b/src/app/(main)/[slug]/page.tsx index cf9988578..dfe51b3cf 100644 --- a/src/app/(main)/[slug]/page.tsx +++ b/src/app/(main)/[slug]/page.tsx @@ -1,22 +1,25 @@ import { Metadata } from "next"; -import { redirect } from "next/navigation"; import { Blog } from "src/blog/Blog"; import BlogPreview from "src/blog/BlogPreview"; -import SalaryAndBenefits from "src/salaryAndBenefits/SalaryAndBenefits"; +import Compensations from "src/compensations/Compensations"; import { getDraftModeInfo } from "src/utils/draftmode"; import SectionRenderer from "src/utils/renderSection"; import { fetchSeoData, generateMetadataFromSeo } from "src/utils/seo"; import { BlogPage, PageBuilder, Post } from "studio/lib/payloads/pages"; -import { SalaryAndBenefitsPage } from "studio/lib/payloads/salaryAndBenefits"; +import { CompensationsPage } from "studio/lib/payloads/compensations"; import { BLOG_PAGE_QUERY, POSTS_QUERY, - SALARY_AND_BENEFITS_PAGE_QUERY, + COMPENSATIONS_PAGE_QUERY, SEO_SLUG_QUERY, SLUG_QUERY, } from "studio/lib/queries/pages"; import { loadQuery } from "studio/lib/store"; -import SalaryAndBenefitsPreview from "src/salaryAndBenefits/SalaryAndBenefitsPreview"; +import CompensationsPreview from "src/compensations/CompensationsPreview"; +import { homeLink } from "../../../blog/components/utils/linkTypes"; +import CustomErrorMessage from "../../../blog/components/customErrorMessage/CustomErrorMessage"; +import { CompanyLocation } from "studio/lib/payloads/companyDetails"; +import { COMPANY_LOCATIONS_QUERY } from "studio/lib/queries/companyDetails"; export const dynamic = "force-dynamic"; @@ -32,33 +35,52 @@ export async function generateMetadata({ params }: Props): Promise { return generateMetadataFromSeo(seo); } +const Page404 = ( + +); + async function Page({ params }: Props) { const { slug } = params; const { perspective, isDraftMode } = getDraftModeInfo(); - const [initialPage, initialBlogPage, initialSalaryAndBenefitsPage] = - await Promise.all([ - loadQuery(SLUG_QUERY, { slug }, { perspective }), - loadQuery(BLOG_PAGE_QUERY, { slug }, { perspective }), - loadQuery( - SALARY_AND_BENEFITS_PAGE_QUERY, - { slug }, - { perspective }, - ), - ]); + const [ + initialPage, + initialBlogPage, + initialCompensationsPage, + initialLocationsData, + ] = await Promise.all([ + loadQuery(SLUG_QUERY, { slug }, { perspective }), + loadQuery(BLOG_PAGE_QUERY, { slug }, { perspective }), + loadQuery( + COMPENSATIONS_PAGE_QUERY, + { slug }, + { perspective }, + ), + loadQuery(COMPANY_LOCATIONS_QUERY, {}, { perspective }), + ]); - if ( - !initialPage.data && - !initialBlogPage.data && - !initialSalaryAndBenefitsPage.data - ) { - console.log(`Page ${slug} not found`); - // TODO: add error snackbar - redirect("/"); + if (initialPage.data) { + return ( + <> + {initialPage.data?.sections?.map((section, index) => ( + + ))} + + ); } - // TODO: fix error for when initialBlogPage.data is empty (say slug doesn't exists) - if (!initialPage.data && initialBlogPage.data) { + if (initialBlogPage.data) { const initialPosts = await loadQuery( POSTS_QUERY, { slug }, @@ -66,8 +88,7 @@ async function Page({ params }: Props) { ); if (!initialPosts) { - console.log(`Posts for page: ${slug} not found`); - // TODO: ADD ERROR PAGE + return Page404; } return isDraftMode ? ( @@ -85,36 +106,21 @@ async function Page({ params }: Props) { ); } - if (initialBlogPage.data && !initialBlogPage.data) { - return ( - <> - {initialPage.data?.sections?.map((section, index) => ( - - ))} - - ); - } - - if (initialSalaryAndBenefitsPage.data) { + if (initialCompensationsPage.data && initialLocationsData.data) { return isDraftMode ? ( - ) : ( - ); } - return null; + return Page404; } export default Page; diff --git a/src/app/(main)/layout.tsx b/src/app/(main)/layout.tsx index b78143f17..9dfeeed10 100644 --- a/src/app/(main)/layout.tsx +++ b/src/app/(main)/layout.tsx @@ -1,9 +1,9 @@ import Footer from "src/components/navigation/footer/Footer"; import { NAV_QUERY } from "studio/lib/queries/navigation"; -import { SITESETTINGS_QUERY } from "studio/lib/queries/siteSettings"; +import { COMPANY_INFO_QUERY } from "studio/lib/queries/companyDetails"; import { Header } from "src/components/navigation/header/Header"; import { Navigation } from "studio/lib/payloads/navigation"; -import { SiteSettings } from "studio/lib/payloads/siteSettings"; +import { CompanyInfo } from "studio/lib/payloads/companyDetails"; import { loadQuery } from "studio/lib/store"; import HeaderPreview from "src/components/navigation/header/HeaderPreview"; import FooterPreview from "src/components/navigation/footer/FooterPreview"; @@ -24,22 +24,22 @@ export default async function Layout({ }>) { const { perspective, isDraftMode } = getDraftModeInfo(); - const [initialNav, initialSiteSettings, initialSoMe, initialLegal] = + const [initialNav, initialCompanyInfo, initialSoMe, initialLegal] = await Promise.all([ loadQuery(NAV_QUERY, {}, { perspective }), - loadQuery(SITESETTINGS_QUERY, {}, { perspective }), + loadQuery(COMPANY_INFO_QUERY, {}, { perspective }), loadQuery(SOMEPROFILES_QUERY, {}, { perspective }), loadQuery(LEGAL_DOCUMENTS_QUERY, {}, { perspective }), ]); const hasNavData = hasValidData(initialNav.data); - const hasSiteSettingsData = hasValidData(initialSiteSettings.data); + const hasCompanyInfoData = hasValidData(initialCompanyInfo.data); const hasHeaderData = hasNavData && (initialNav.data.main || initialNav.data.sidebar); const hasFooterData = hasNavData && initialNav.data.footer; - const hasMenuData = hasSiteSettingsData && (hasHeaderData || hasFooterData); + const hasMenuData = hasCompanyInfoData && (hasHeaderData || hasFooterData); if (!hasMenuData) { return ( @@ -55,12 +55,12 @@ export default async function Layout({ {hasHeaderData && isDraftMode ? ( ) : (
)}
@@ -69,14 +69,14 @@ export default async function Layout({ {hasFooterData && isDraftMode ? ( ) : (