diff --git a/__tests__/gatsby-theme-project-portal/SearchBar.spec.tsx b/__tests__/gatsby-theme-project-portal/SearchBar.spec.tsx index 048f9fb02..399e0378a 100644 --- a/__tests__/gatsby-theme-project-portal/SearchBar.spec.tsx +++ b/__tests__/gatsby-theme-project-portal/SearchBar.spec.tsx @@ -8,7 +8,12 @@ describe("SearchBar", () => { it("renders label and input elements with the correct props", () => { const { getByLabelText, getByText } = render( - + ) //looking for text set to "Test Label" expect(getByText("Test Label")).toBeInTheDocument() @@ -18,7 +23,12 @@ describe("SearchBar", () => { it("calls the onChange callback when the input value changes", () => { const { getByLabelText } = render( - + ) //fireEvent.change to simulate the input value change //trigger's a change event on the input element @@ -30,7 +40,12 @@ describe("SearchBar", () => { it("renders the input placeholder correctly", () => { const { getByPlaceholderText } = render( - + ) //check placeholder text expect(getByPlaceholderText("Type to filter posts...")).toBeInTheDocument() @@ -38,7 +53,12 @@ describe("SearchBar", () => { it("sets the aria-label attribute to the correct value", () => { const { getByLabelText } = render( - + ) //checks that aria-label is set correctly expect(getByLabelText("Search")).toHaveAttribute("aria-label", "Search") @@ -46,7 +66,12 @@ describe("SearchBar", () => { it("applies the correct CSS classes to the input element", () => { const { getByLabelText } = render( - + ) //checks that tailwind styling is correct expect(getByLabelText("Search")).toHaveClass( @@ -58,7 +83,12 @@ describe("SearchBar", () => { it("sets the htmlFor attribute on the label element", () => { const { getByText } = render( - + ) //check rendered component has attribute id = search-label expect(getByText("Test Label")).toHaveAttribute("id", "search-label") @@ -66,7 +96,12 @@ describe("SearchBar", () => { it("applies the style prop correctly to the input element", () => { const { getByLabelText } = render( - + ) expect(getByLabelText("Search")).toHaveStyle({ height: "62%" }) }) diff --git a/packages/example-site/content/config/layout.json b/packages/example-site/content/config/layout.json index e6ebe4c8c..b6063f7f7 100644 --- a/packages/example-site/content/config/layout.json +++ b/packages/example-site/content/config/layout.json @@ -33,6 +33,11 @@ "name": "Contact", "link": "/contact/", "show": true + }, + { + "name": "Search", + "link": "/search/", + "show": true } ] }, diff --git a/packages/example-site/content/page/search.json b/packages/example-site/content/page/search.json new file mode 100644 index 000000000..d7a90497d --- /dev/null +++ b/packages/example-site/content/page/search.json @@ -0,0 +1,5 @@ +{ + "templateKey": "SearchPage", + "title": "Search the Whole Site!", + "image": "background.jpg" +} diff --git a/packages/gatsby-theme-project-portal/gatsby-node.js b/packages/gatsby-theme-project-portal/gatsby-node.js index da1d2d860..6ba0a9a51 100644 --- a/packages/gatsby-theme-project-portal/gatsby-node.js +++ b/packages/gatsby-theme-project-portal/gatsby-node.js @@ -1,6 +1,6 @@ const { withDefaults } = require(`./utils/default-options`) const fs = require("fs") - +const { createSearchIndex, searchQuery } = require(`./utils/search`) const { siteMetadataTypeDefs, projectTypeDefs, @@ -46,6 +46,13 @@ exports.createPages = async ({ graphql, actions, reporter }) => { } } } + searchPages: allGeneralPage( + filter: { templateKey: { eq: "SearchPage" } } + ) { + nodes { + slug + } + } aboutPages: allGeneralPage(filter: { templateKey: { eq: "AboutPage" } }) { nodes { slug @@ -60,7 +67,6 @@ exports.createPages = async ({ graphql, actions, reporter }) => { } } `) - if (result.errors) { reporter.panicOnBuild(result.errors) } @@ -97,6 +103,18 @@ exports.createPages = async ({ graphql, actions, reporter }) => { }) }) + const { searchPages } = result.data + searchPages.nodes.forEach((page) => { + const { slug } = page + createPage({ + path: `/${slug}`, + component: require.resolve(`./src/layouts/SearchPageLayout.tsx`), + context: { + slug: slug, + }, + }) + }) + const { aboutPages } = result.data aboutPages.nodes.forEach((page) => { const { slug } = page @@ -129,3 +147,38 @@ exports.createPages = async ({ graphql, actions, reporter }) => { }) }) } + +exports.onPreBuild = async ({ reporter, basePath, pathPrefix, graphql }) => { + const result = await graphql(searchQuery) + const { allProject, allGeneralPage } = result.data + + const [index, documents] = createSearchIndex({ allProject, allGeneralPage }) + await fs.writeFile("static/lunr-index.json", JSON.stringify(index), (err) => { + if (err) console.error(err) + }) + await fs.writeFile( + "static/documents.json", + JSON.stringify(documents), + (err) => { + if (err) console.error(err) + } + ) + // this is a function which grabs the page from the original documents + // lunr tosses this info for SPEED + const reduceDocuments = documents.reduce(function (page, document) { + page[document.slug] = document + return page + }, {}) + + await fs.writeFile( + "static/documents-reduced.json", + JSON.stringify(reduceDocuments), + (err) => { + if (err) console.error(err) + } + ) + + reporter.info( + `Site was built with basePath: ${basePath} & pathPrefix: ${pathPrefix}` + ) +} diff --git a/packages/gatsby-theme-project-portal/package.json b/packages/gatsby-theme-project-portal/package.json index 4a808e7f0..3dd07f1c5 100644 --- a/packages/gatsby-theme-project-portal/package.json +++ b/packages/gatsby-theme-project-portal/package.json @@ -33,6 +33,7 @@ "gatsby-transformer-sharp": "^5.12.3", "js-search": "^2.0.1", "lodash": "^4.17.21", + "lunr": "^2.3.9", "markdown-to-jsx": "^7.3.2", "moment": "^2.29.4", "react-google-recaptcha": "^3.1.0", diff --git a/packages/gatsby-theme-project-portal/src/components/Label.tsx b/packages/gatsby-theme-project-portal/src/components/Label.tsx new file mode 100644 index 000000000..5562a3d1d --- /dev/null +++ b/packages/gatsby-theme-project-portal/src/components/Label.tsx @@ -0,0 +1,16 @@ +import React, { FunctionComponent } from "react" + +interface LabelProps { + id: string + label: string +} + +export const Label: FunctionComponent = ({ id, label }) => { + return ( + <> + + + ) +} diff --git a/packages/gatsby-theme-project-portal/src/components/ProjectDetail.stories.tsx b/packages/gatsby-theme-project-portal/src/components/ProjectDetail.stories.tsx index addbc9ad6..62a4fefed 100644 --- a/packages/gatsby-theme-project-portal/src/components/ProjectDetail.stories.tsx +++ b/packages/gatsby-theme-project-portal/src/components/ProjectDetail.stories.tsx @@ -58,6 +58,78 @@ export const Primary: Story = { }, } +export const LongTitle: Story = { + args: { + title: "completed 2", + agency: "example agency", + topics: [], + slug: "project/completed-project", + summary: "example project summary", + statusOfData: "example statusOfData", + status: "completed", + startDate: new Date("2022-06-17"), + requirement: "example requirement", + question: + "Hello world2 (from json)? Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua?", + purpose: "example purpose", + projectTeam: ProjectTeamStories.Primary.args.contacts, + priorResearch: null, + opportunityCloses: new Date("2022-10-28"), + mainContact: { + name: "Contact Name", + title: "Title", + employer: "Employer", + email: "some-email@example.com", + image: contactImageYogi, + }, + fundingInfo: "example fundingInfo", + expertise: "example expertise", + faq: [ + { title: "Question 1?", text: "Answer 1!" }, + { + title: "This is another different question?", + text: "Here's an answer for that question! Yay!", + }, + ], + deliverable: "example deliverable", + emailContent: "example emailContent", + endDate: new Date("2016-12-15"), + }, +} + +export const NullValues: Story = { + args: { + title: "project completed 2", + agency: "example agency", + topics: [], + slug: "project/completed-project2", + summary: "", + statusOfData: null, + status: "completed", + startDate: new Date("2022-06-17"), + requirement: null, + question: "", + purpose: null, + projectTeam: ProjectTeamStories.Primary.args.contacts, + priorResearch: null, + opportunityCloses: new Date("2022-10-28"), + mainContact: { + name: "Contact Name", + title: "Title", + employer: "Employer", + email: "some-email@example.com", + image: contactImageYogi, + }, + keyDates: null, + fundingInfo: null, + expertise: null, + faq: null, + deliverable: null, + emailContent: null, + endDate: new Date("2016-12-15"), + }, +} + export const Open: Story = { args: { ...Primary.args, status: "open" }, } @@ -93,6 +165,58 @@ export const Minimum: Story = { }, } +export const Maximum: Story = { + args: { + question: "Is there a difference between brown sugar and white sugar?", + summary: + "Contrary to common belief, they are nutritionally similar. Nutritionally speaking, all natural sugars have relatively comparable nutritional value with approximately 15 calories per teaspoon (4.2 g).\n", + title: "Sugar Investigations in the US", + mainContact: { + name: "Contact Name", + title: "Title", + employer: "Employer", + email: "some-email@example.com", + }, + + status: "open", + opportunityCloses: new Date("2022-03-04"), + startDate: new Date("2022-01-03"), + endDate: new Date("2022-03-04"), + agency: "Sugar Agency", + topics: [ + { slug: "conspiracy", title: "conspiracy" }, + { slug: "investigation", title: "investigation" }, + ], + lastModified: new Date("2022-05-27T16:34:04.000Z"), + slug: "project/sugar-investigations", + emailContent: + "Dearest community, Are you interested in knowing about sugars? So are we! Join our search!", + deliverable: + "Analysis of existing sugars in the United States. Summary of and detailed recommendations and potential action steps to inform the public about the sugars they are consuming.  \\n* See project summary for additional information.", + purpose: + "Results will be shared with the FDA and whoever else wants these results. We have no oversight and thus may do as we wish.", + expertise: + "While our team does not have previous experience in organic chemistry, we are committed to uncovering the truth.", + requirement: "I do not understand this question. Next.", + keyDates: "Publish data at some point in time.", + priorResearch: "Prior research is published in many reputable journals.", + statusOfData: "Data collection has not begun.", + fundingInfo: + "Our team will evaluate whether or not a project needs money, and we will most likely need the project team to figure out funding.", + openText: "Are you interested in collaborating?", + ongoingText: "This project is ongoing.", + completeText: "This project is complete.", + projectTeam: ProjectTeamStories.Primary.args.contacts, + faq: [ + { title: "Question 1?", text: "Answer 1!" }, + { + title: "This is another question?", + text: "Here's an answer for that question! Yay!", + }, + ], + }, +} + export const TailwindXSWindow: Story = { args: Primary.args, parameters: { viewport: { defaultViewport: "tailwindXS" } }, diff --git a/packages/gatsby-theme-project-portal/src/components/ProjectDetail.tsx b/packages/gatsby-theme-project-portal/src/components/ProjectDetail.tsx index 0775f4db3..62620694b 100644 --- a/packages/gatsby-theme-project-portal/src/components/ProjectDetail.tsx +++ b/packages/gatsby-theme-project-portal/src/components/ProjectDetail.tsx @@ -18,6 +18,7 @@ import { statusOutput, isNA, isEmpty } from "../utils" export interface ProjectDetailProps { // Core content question: string + slug?: string summary: string title: string @@ -57,17 +58,19 @@ export interface ProjectDetailProps { agency: string topics?: TopicType[] lastModified: Date - + emailContent?: String defaultContactImage: ImageDataLike } export const ProjectDetail: FunctionComponent = ({ question, + slug, summary, status, opportunityCloses, startDate, endDate, + emailContent, lastModified, agency, topics, diff --git a/packages/gatsby-theme-project-portal/src/components/ProjectPage.tsx b/packages/gatsby-theme-project-portal/src/components/ProjectPage.tsx index 827c56941..3bfe47156 100644 --- a/packages/gatsby-theme-project-portal/src/components/ProjectPage.tsx +++ b/packages/gatsby-theme-project-portal/src/components/ProjectPage.tsx @@ -7,6 +7,7 @@ import Select, { MultiValue } from "react-select" import * as JsSearch from "js-search" import { SearchBar } from "./SearchBar" import { ImageDataLike } from "gatsby-plugin-image" +import { Label } from "./Label" function customSort(dateField: string, sortAscending: boolean) { return function (a, b) { @@ -241,11 +242,9 @@ export const ProjectPage = ({
-
+
- +