From 8a10d127c1a6dbb396903375299f7c45bf8a96d6 Mon Sep 17 00:00:00 2001 From: Unknown <_> Date: Fri, 17 Jul 2026 22:22:29 +0100 Subject: [PATCH] feat: feed feature, typescript, remove google, fix errs & warns --- .gitea/workflows/publish.yml | 2 +- .github/workflows/publish.yml | 4 +- .nvmrc | 2 +- README.md | 11 + content/feed/welcome-to-the-feed/index.md | 21 + docs/adding-feed-posts.md | 96 ++ gatsby-browser.js | 1 + gatsby-config.d.ts | 15 + gatsby-config.js | 75 +- gatsby-node.js | 173 +++- package-lock.json | 844 +++++++++++++----- package.json | 32 +- src/components/footer/index.tsx | 47 +- src/components/footer/{style.js => style.tsx} | 9 +- src/components/herosection/index.tsx | 14 +- .../herosection/{style.js => style.tsx} | 5 +- src/components/layout.tsx | 8 +- src/components/navibar/index.tsx | 57 +- .../navibar/{style.js => style.tsx} | 13 +- src/components/seo.tsx | 73 +- src/components/shared/container.tsx | 9 +- src/components/shared/scheduleDemo.tsx | 2 +- src/components/shared/section.tsx | 14 +- ...yledComponents.js => styledComponents.tsx} | 20 +- src/controllers/NostrController.ts | 12 +- src/pages/404.tsx | 11 +- src/pages/about.tsx | 16 +- src/pages/contact.tsx | 32 +- src/pages/faq.tsx | 16 +- src/pages/index.tsx | 42 +- .../{MarkdownRemark.frontmatter__slug}.tsx | 23 +- src/styledComponents/{about.js => about.tsx} | 0 src/styledComponents/{blog.js => blog.tsx} | 3 +- src/styledComponents/contact.js | 17 - src/styledComponents/contact.tsx | 20 + src/styledComponents/{faq.js => faq.tsx} | 9 +- src/styledComponents/{index.js => index.tsx} | 32 +- src/styles/montserrat.css | 35 + src/templates/blog-list.tsx | 42 +- src/templates/blog-post.tsx | 14 +- src/templates/blog-search.tsx | 28 +- src/templates/feed-list.tsx | 131 +++ src/templates/feed-post.tsx | 71 ++ src/templates/post/index.tsx | 37 +- src/templates/postpreview/index.tsx | 53 +- src/templates/shared/getDescription.ts | 2 +- src/templates/sidebar.tsx | 86 +- src/types/assets.d.ts | 25 + src/types/declarations.d.ts | 10 + src/types/index.ts | 1 + src/types/site.ts | 139 +++ static/fonts/Montserrat-300.woff2 | Bin 0 -> 18708 bytes static/fonts/Montserrat-400.woff2 | Bin 0 -> 18780 bytes static/fonts/Montserrat-500.woff2 | Bin 0 -> 18748 bytes tsconfig.json | 20 + 55 files changed, 1887 insertions(+), 587 deletions(-) create mode 100644 content/feed/welcome-to-the-feed/index.md create mode 100644 docs/adding-feed-posts.md create mode 100644 gatsby-config.d.ts rename src/components/footer/{style.js => style.tsx} (79%) rename src/components/herosection/{style.js => style.tsx} (78%) rename src/components/navibar/{style.js => style.tsx} (97%) rename src/components/shared/{styledComponents.js => styledComponents.tsx} (76%) rename src/styledComponents/{about.js => about.tsx} (100%) rename src/styledComponents/{blog.js => blog.tsx} (63%) delete mode 100644 src/styledComponents/contact.js create mode 100644 src/styledComponents/contact.tsx rename src/styledComponents/{faq.js => faq.tsx} (78%) rename src/styledComponents/{index.js => index.tsx} (73%) create mode 100644 src/styles/montserrat.css create mode 100644 src/templates/feed-list.tsx create mode 100644 src/templates/feed-post.tsx create mode 100644 src/types/assets.d.ts create mode 100644 src/types/declarations.d.ts create mode 100644 src/types/site.ts create mode 100644 static/fonts/Montserrat-300.woff2 create mode 100644 static/fonts/Montserrat-400.woff2 create mode 100644 static/fonts/Montserrat-500.woff2 create mode 100644 tsconfig.json diff --git a/.gitea/workflows/publish.yml b/.gitea/workflows/publish.yml index 6b804c1..17d0569 100644 --- a/.gitea/workflows/publish.yml +++ b/.gitea/workflows/publish.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version-file: '.nvmrc' cache: 'npm' - name: Install dependencies diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3504055..305cc2b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,10 +11,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20 + - name: Use Node.js from .nvmrc uses: actions/setup-node@v4 with: - node-version: 20 + node-version-file: .nvmrc cache: npm - name: Install dependencies diff --git a/.nvmrc b/.nvmrc index c675bca..5bcf9c6 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v20.20.2 +v24.18.0 diff --git a/README.md b/README.md index 33b7f22..4d53dd2 100644 --- a/README.md +++ b/README.md @@ -30,3 +30,14 @@ - Title - Title + +## 📰 Blog & Feed content + +There are two markdown-driven content sections on this site: + +- **Blog** (`content/blog/`) — long-form articles, product releases and case studies. Published at `/blog/`. +- **Feed** (`content/feed/`) — short announcements and social-media style updates. Published at `/feed/`. + +Both sections are combined into a single RSS feed at [`/rss.xml`](https://datacontroller.io/rss.xml). + +See [`docs/adding-feed-posts.md`](docs/adding-feed-posts.md) for a step-by-step guide on adding a new Feed post. diff --git a/content/feed/welcome-to-the-feed/index.md b/content/feed/welcome-to-the-feed/index.md new file mode 100644 index 0000000..81375d2 --- /dev/null +++ b/content/feed/welcome-to-the-feed/index.md @@ -0,0 +1,21 @@ +--- +title: "Welcome to the Data Controller Feed" +description: A new home for quick announcements, social media updates and other bite-sized news from the Data Controller team. +date: '2026-07-17 09:00:00' +author: 'Data Controller' +authorLink: https://www.linkedin.com/showcase/data_controller +tags: + - Announcements +--- + +# Welcome to the Feed + +We're launching a new **Feed** section on the Data Controller website! This is where you'll find: + +- Quick announcements +- Social media style updates +- Smaller news items that don't warrant a full blog post + +It sits alongside our [Blog](/blog/) and both are combined into a single [RSS feed](/rss.xml) so you can subscribe once and get everything in one place. + +Stay tuned for more updates! diff --git a/docs/adding-feed-posts.md b/docs/adding-feed-posts.md new file mode 100644 index 0000000..2d9c3b4 --- /dev/null +++ b/docs/adding-feed-posts.md @@ -0,0 +1,96 @@ +# Adding a Feed Post + +The **Feed** section (`/feed/`) is for short announcements and social-media +style updates — things that don't warrant a full [`content/blog/`](../content/blog) +article, but are still worth publishing and syndicating via RSS. + +Feed posts work exactly like blog posts (one markdown file per post, in its +own directory), but live under `content/feed/` instead of `content/blog/`, +and are published under `/feed/` instead of `/blog/`. + +Both sections share a single combined RSS feed at +[`/rss.xml`](https://datacontroller.io/rss.xml) (see `gatsby-plugin-feed` in +[`gatsby-config.js`](../gatsby-config.js)), so a new Feed post automatically +appears in the RSS feed the next time the site is built — no extra +configuration required. + +A visible "RSS Feed" link (pointing to `/rss.xml`) is rendered in two places +so visitors can discover and subscribe to it: + +- The site-wide [`Footer`](../src/components/footer/index.tsx), under + "Other Resources". +- The "Subscribe" section of the shared + [`SideBar`](../src/templates/sidebar.tsx), shown on Blog and Feed list/post + pages. + +## 1. Create a new post directory + +Create a new folder under `content/feed/`, named after the post slug (this +becomes the URL): + +``` +content/feed/my-new-announcement/index.md +``` + +## 2. Write the frontmatter + content + +```md +--- +title: 'My New Announcement' +description: A one or two sentence summary used for SEO and RSS. +date: '2024-06-01 09:00:00' +author: 'Your Name' +authorLink: https://www.linkedin.com/in/yourprofile/ +tags: + - Announcements +--- + +Your announcement content goes here, written in regular Markdown. +``` + +Notes on frontmatter fields: + +| Field | Required | Notes | +| ------------- | -------- | ---------------------------------------------------------------------- | +| `title` | Yes | Post title, used on the page, in the sidebar and in the RSS item. | +| `description` | Yes | Short summary, used for SEO meta tags and the RSS item description. | +| `date` | Yes | Format `'YYYY-MM-DD HH:MM:SS'`. Controls sort order and the archive. | +| `author` | Yes | Displayed under the post title. | +| `authorLink` | No | If set, the author name links out (e.g. to a LinkedIn profile). | +| `tags` | Yes | One or more tags. Used for the sidebar category list and RSS ``. | +| `previewImg` | No | Optional relative path to an image in the same folder (e.g. `'./cover.png'`). Feed posts commonly omit this since they're short-form. | + +## 3. Add any images (optional) + +If you use `previewImg` or reference images in the body, place the image +files in the same post directory and reference them with a relative path, +the same as for blog posts. + +## 4. Build / preview + +```shell +npm run develop +``` + +Your new post will be available at `/my-new-announcement/`, and will appear: + +- On the [`/feed/`](https://datacontroller.io/feed/) listing page (with + pagination, sidebar archives and tag categories under `/feed/...`). +- In the site search index. +- In the combined RSS feed at `/rss.xml`, alongside blog posts. + +## How it differs from a Blog post + +| Aspect | Blog | Feed | +| ------------------ | ------------------------------ | ----------------------------------- | +| Content directory | `content/blog/` | `content/feed/` | +| Listing page | `/blog/` | `/feed/` | +| Year archive | `/{year}/` | `/feed/{year}/` | +| Category page | `/category/{tag}/` | `/feed/category/{tag}/` | +| Template | `src/templates/blog-post.tsx`, `src/templates/blog-list.tsx` | `src/templates/feed-post.tsx`, `src/templates/feed-list.tsx` | +| RSS | Included in `/rss.xml` | Included in `/rss.xml` | + +Feed archive/category routes are prefixed with `/feed/` specifically to avoid +colliding with the equivalent Blog routes, since both content types are +rendered by the shared [`src/templates/sidebar.tsx`](../src/templates/sidebar.tsx) +component (via its `basePath` prop). diff --git a/gatsby-browser.js b/gatsby-browser.js index f68fc25..7dc8fe1 100644 --- a/gatsby-browser.js +++ b/gatsby-browser.js @@ -1,4 +1,5 @@ import "bootstrap/dist/css/bootstrap.min.css"; +import "./src/styles/montserrat.css"; // Import all js dependencies. import "jquery/dist/jquery.min.js"; diff --git a/gatsby-config.d.ts b/gatsby-config.d.ts new file mode 100644 index 0000000..e44cc64 --- /dev/null +++ b/gatsby-config.d.ts @@ -0,0 +1,15 @@ +export interface SiteMetadata { + title: string + description: string + siteUrl: string + author: { + name: string + summary: string + } + social: { + linkedin: string + } +} + +export const siteMetadata: SiteMetadata +export const pathPrefix: string diff --git a/gatsby-config.js b/gatsby-config.js index 13ecd09..3782e24 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -23,7 +23,6 @@ module.exports = { name: `Data Controller | Flexible and Secure SAS® Data Modification`, short_name: `Data Controller`, description: `Data Controller for SAS® is dedicated to helping users, admins and developers manage their data. A zero code approach with Data Lineage, Catalog, Dictionary, Validation, Workflow, Alerts and more.`, - homepage_url: 'https://datacontroller.io/', start_url: '/', background_color: '#fff', theme_color: '#314351', @@ -51,6 +50,14 @@ module.exports = { }, __key: 'blog' }, + { + resolve: `gatsby-source-filesystem`, + options: { + path: `./content/feed`, + name: `feed` + }, + __key: 'feed' + }, { resolve: `gatsby-source-filesystem`, options: { @@ -103,13 +110,6 @@ module.exports = { }, __key: 'pages' }, - { - resolve: `gatsby-plugin-google-fonts`, - options: { - fonts: [`Montserrat\:300,400,500`], - display: 'swap' - } - }, { resolve: 'gatsby-plugin-local-search', options: { @@ -131,7 +131,7 @@ module.exports = { // required. query: ` { - remark: allMarkdownRemark (filter: {fileAbsolutePath: {regex: "/content/blog/"}}) { + remark: allMarkdownRemark (filter: {fileAbsolutePath: {regex: "/content\\/(blog|feed)\\//"}}) { posts: edges { post: node { id @@ -184,6 +184,63 @@ module.exports = { html: data.post.html })) } + }, + { + resolve: 'gatsby-plugin-feed', + options: { + query: ` + { + site { + siteMetadata { + title + description + siteUrl + } + } + } + `, + feeds: [ + { + serialize: ({ query: { site, allMarkdownRemark } }) => + allMarkdownRemark.nodes.map((node) => ({ + title: node.frontmatter.title, + description: node.frontmatter.description || '', + date: node.frontmatter.date, + url: site.siteMetadata.siteUrl + node.fields.slug, + guid: site.siteMetadata.siteUrl + node.fields.slug, + author: node.frontmatter.author, + categories: node.frontmatter.tags || [], + custom_elements: [{ 'content:encoded': node.html }] + })), + query: ` + { + allMarkdownRemark( + sort: { frontmatter: { date: DESC } } + filter: { + fileAbsolutePath: { regex: "/content\\/(blog|feed)\\//" } + } + ) { + nodes { + html + fields { + slug + } + frontmatter { + title + description + date + author + tags + } + } + } + } + `, + output: '/rss.xml', + title: 'Data Controller — Blog & Feed' + } + ] + } } ] } diff --git a/gatsby-node.js b/gatsby-node.js index c858544..878a702 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -6,6 +6,10 @@ const recentPosts = [] const archives = {} const tagsFrequent = [] +const feedRecentPosts = [] +const feedArchives = {} +const feedTagsFrequent = [] + exports.createPages = async ({ graphql, actions, reporter }) => { const { createPage } = actions @@ -14,6 +18,10 @@ exports.createPages = async ({ graphql, actions, reporter }) => { const blogListTemplate = path.resolve(`./src/templates/blog-list.tsx`) const blogSearchTemplate = path.resolve(`./src/templates/blog-search.tsx`) + // Define a template for feed post + const feedPostTemplate = path.resolve(`./src/templates/feed-post.tsx`) + const feedListTemplate = path.resolve(`./src/templates/feed-list.tsx`) + // Get all markdown blog posts sorted by date const result = await graphql( ` @@ -34,7 +42,10 @@ exports.createPages = async ({ graphql, actions, reporter }) => { } } } - tagsGroup: allMarkdownRemark(limit: 1000) { + tagsGroup: allMarkdownRemark( + limit: 1000 + filter: { fileAbsolutePath: { regex: "/content/blog/" } } + ) { group(field: { frontmatter: { tags: SELECT } }) { name: fieldValue totalCount @@ -176,6 +187,166 @@ exports.createPages = async ({ graphql, actions, reporter }) => { tags: tagsFrequent } }) + + // --------------------------------------------------------------------- + // Feed section (announcements / social updates) - mirrors the blog logic + // above but is scoped to /content/feed/ and lives under the /feed/ path + // --------------------------------------------------------------------- + + const feedResult = await graphql( + ` + { + allMarkdownRemark( + sort: { frontmatter: { date: DESC } } + limit: 1000 + filter: { fileAbsolutePath: { regex: "/content/feed/" } } + ) { + nodes { + id + fields { + slug + } + frontmatter { + title + date(formatString: "YYYY") + } + } + } + tagsGroup: allMarkdownRemark( + limit: 1000 + filter: { fileAbsolutePath: { regex: "/content/feed/" } } + ) { + group(field: { frontmatter: { tags: SELECT } }) { + name: fieldValue + totalCount + } + } + } + ` + ) + + if (feedResult.errors) { + reporter.panicOnBuild( + `There was an error loading your feed posts`, + feedResult.errors + ) + return + } + + const feedPosts = feedResult.data.allMarkdownRemark.nodes + feedRecentPosts.push( + ...feedPosts.slice(0, 10).map((p) => ({ + slug: p.fields.slug, + title: p.frontmatter.title + })) + ) + + const feedTags = feedResult.data.tagsGroup.group + feedTagsFrequent.push( + ...feedTags.sort((a, b) => b.totalCount - a.totalCount).slice(0, 10) + ) + + feedPosts.forEach((d) => { + if (feedArchives[d.frontmatter.date] == null) + feedArchives[d.frontmatter.date] = 0 + feedArchives[d.frontmatter.date]++ + }) + + // Create individual feed post pages + if (feedPosts.length > 0) { + feedPosts.forEach((post, index) => { + const previousPostId = index === 0 ? null : feedPosts[index - 1].id + const nextPostId = + index === feedPosts.length - 1 ? null : feedPosts[index + 1].id + + createPage({ + path: post.fields.slug, + component: feedPostTemplate, + context: { + id: post.id, + archives: feedArchives, + recentPosts: feedRecentPosts, + tags: feedTagsFrequent, + previousPostId, + nextPostId + } + }) + }) + } + + // Create feed-list pages + const feedNumPages = Math.ceil(feedPosts.length / postsPerPage) + Array.from({ length: feedNumPages }).forEach((_, i) => { + createPage({ + path: i === 0 ? `/feed` : `/feed/page/${i + 1}`, + component: feedListTemplate, + context: { + page: 'index', + archives: feedArchives, + recentPosts: feedRecentPosts, + tags: feedTagsFrequent, + filter: { fileAbsolutePath: { regex: '/content/feed/' } }, + limit: postsPerPage, + skip: i * postsPerPage, + numPages: feedNumPages, + currentPage: i + 1 + } + }) + }) + + for (year in feedArchives) { + const count = feedArchives[year] + const numPagesOfYear = Math.ceil(count / postsPerPage) + Array.from({ length: numPagesOfYear }).forEach((_, i) => { + createPage({ + path: + i === 0 ? `/feed/${year}/` : `/feed/${year}/page/${i + 1}`, + component: feedListTemplate, + context: { + page: 'year', + archives: feedArchives, + recentPosts: feedRecentPosts, + tags: feedTagsFrequent, + filter: { + frontmatter: { date: { gte: year, lt: year + 1 } }, + fileAbsolutePath: { regex: '/content/feed/' } + }, + limit: postsPerPage, + skip: i * postsPerPage, + numPages: numPagesOfYear, + currentPage: i + 1, + year: year + } + }) + }) + } + + feedTags.forEach((tag) => { + const count = tag.totalCount + const numPagesOfTag = Math.ceil(count / postsPerPage) + Array.from({ length: numPagesOfTag }).forEach((__, i) => { + const tagPath = `/feed/category/${_.kebabCase(tag.name)}/` + createPage({ + path: i === 0 ? tagPath : `${tagPath}page/${i + 1}`, + component: feedListTemplate, + context: { + page: 'category', + archives: feedArchives, + recentPosts: feedRecentPosts, + tags: feedTagsFrequent, + filter: { + frontmatter: { tags: { in: [tag.name] } }, + fileAbsolutePath: { regex: '/content/feed/' } + }, + limit: postsPerPage, + skip: i * postsPerPage, + numPages: numPagesOfTag, + currentPage: i + 1, + tag: tag.name + } + }) + }) + }) } exports.onCreatePage = ({ page, actions }) => { diff --git a/package-lock.json b/package-lock.json index 7010354..0878495 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,9 +12,10 @@ "@mdx-js/mdx": "^3.1.1", "@mdx-js/react": "^3.1.1", "babel-plugin-styled-components": "^2.1.4", + "baseline-browser-mapping": "^2.10.43", + "caniuse-lite": "^1.0.30001806", "gatsby": "^5.15.0", - "gatsby-plugin-google-analytics": "^5.13.1", - "gatsby-plugin-google-fonts": "^1.0.1", + "gatsby-plugin-feed": "^5.16.0", "gatsby-plugin-image": "^3.15.0", "gatsby-plugin-local-search": "^2.0.1", "gatsby-plugin-manifest": "^5.15.0", @@ -41,9 +42,19 @@ }, "devDependencies": { "@popperjs/core": "^2.9.2", + "@types/lodash": "^4.17.24", + "@types/node": "^20.19.43", + "@types/react": "^18.3.31", + "@types/react-dom": "^18.3.7", + "@types/react-helmet": "^6.1.11", "bootstrap": "^5.0.0-beta3", "cloudron-surfer": "^6.4.1", - "jquery": "^3.6.0" + "jquery": "^3.6.0", + "typescript": "^7.0.2" + }, + "engines": { + "node": ">=24.0.0", + "npm": ">=10.0.0" } }, "node_modules/@ampproject/remapping": { @@ -2165,6 +2176,23 @@ "node": ">= 4" } }, + "node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, "node_modules/@expo/devcert": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.2.1.tgz", @@ -2771,72 +2799,78 @@ } }, "node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.3.tgz", - "integrity": "sha512-RXwGZ/0eCqtCY8FLTM/koR60w+MXyvBUpToXiIyjOcBnC81tAlTUHrRUavCEWPI9zc9VgvpK3+cbumPyR8BSuA==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.9.4.tgz", + "integrity": "sha512-38XmbES/wVcvMXdwcM5QzL0cSaZu3VwE7mCd0I89eliHQTMQblgWXsr2HQoP9v0JnH6jVt7+E/TkeGNLmp4wzA==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.3.tgz", - "integrity": "sha512-337dNzh5yCdNCTk8kPfoU7jR3otibSlPDGW0vKZT97rKnQMb9tNdto3RtWoGPsQ8hKmlRZpojOJtmwjncq1MoA==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.9.4.tgz", + "integrity": "sha512-JkPrV8rEu88FzMcuouZeU2b/NuVC3KwQxKo5vKhNycBtsCn7KCWHalxL4sdTiHQ4xtgMca3mmeDAdxgqQqnDig==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@lmdb/lmdb-linux-arm": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.3.tgz", - "integrity": "sha512-mU2HFJDGwECkoD9dHQEfeTG5mp8hNS2BCfwoiOpVPMeapjYpQz9Uw3FkUjRZ4dGHWKbin40oWHuL0bk2bCx+Sg==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.9.4.tgz", + "integrity": "sha512-b3JZL5pLuvcGEbcsThUQPFlQdBFaBxImrlNbFUeJmzLwpdgGRi0RSQdZZ2PuIoZvpRj0tfNlhXQwXiYMz+9iTw==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.3.tgz", - "integrity": "sha512-VJw60Mdgb4n+L0fO1PqfB0C7TyEQolJAC8qpqvG3JoQwvyOv6LH7Ib/WE3wxEW9nuHmVz9jkK7lk5HfWWgoO1Q==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.9.4.tgz", + "integrity": "sha512-aIzmw0g4Wdd/w2rDppGfo1JEl4xWpg6HPbf5ZeuWXCjFms8oc8cazm6oBEAimiZEgYYBFPDPdM644xJcwuJbxQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@lmdb/lmdb-linux-x64": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.3.tgz", - "integrity": "sha512-qaReO5aV8griBDsBr8uBF/faO3ieGjY1RY4p8JvTL6Mu1ylLrTVvOONqKFlNaCwrmUjWw5jnf7VafxDAeQHTow==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.9.4.tgz", + "integrity": "sha512-Yj6Nb+/j+ZZ65oH/UCE0UfUu/6TO5wWLIeE2izGCpsCxcozZVbzwhzrCs0FUXf6lXv46DJteONosWH9o1XjzqQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@lmdb/lmdb-win32-x64": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.3.tgz", - "integrity": "sha512-cK+Elf3RjEzrm3SerAhrFWL5oQAsZSJ/LmjL1joIpTfEP1etJJ9CTRvdaV6XLYAxaEkfdhk/9hOvHLbR9yIhCA==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.9.4.tgz", + "integrity": "sha512-0L6Tyun47/kQb+FzTDIumrfZgU6oEos0RgekKa/3YC7nsUY+ZASZHikzGgEZpMQHSz5YeR+DDUtOMSwqodWHDg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -3107,112 +3141,6 @@ "@parcel/core": "^2.8.3" } }, - "node_modules/@parcel/cache/node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz", - "integrity": "sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@parcel/cache/node_modules/@lmdb/lmdb-darwin-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz", - "integrity": "sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@parcel/cache/node_modules/@lmdb/lmdb-linux-arm": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz", - "integrity": "sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@parcel/cache/node_modules/@lmdb/lmdb-linux-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz", - "integrity": "sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@parcel/cache/node_modules/@lmdb/lmdb-linux-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz", - "integrity": "sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@parcel/cache/node_modules/@lmdb/lmdb-win32-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz", - "integrity": "sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@parcel/cache/node_modules/lmdb": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.5.2.tgz", - "integrity": "sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "msgpackr": "^1.5.4", - "node-addon-api": "^4.3.0", - "node-gyp-build-optional-packages": "5.0.3", - "ordered-binary": "^1.2.4", - "weak-lru-cache": "^1.2.2" - }, - "optionalDependencies": { - "@lmdb/lmdb-darwin-arm64": "2.5.2", - "@lmdb/lmdb-darwin-x64": "2.5.2", - "@lmdb/lmdb-linux-arm": "2.5.2", - "@lmdb/lmdb-linux-arm64": "2.5.2", - "@lmdb/lmdb-linux-x64": "2.5.2", - "@lmdb/lmdb-win32-x64": "2.5.2" - } - }, - "node_modules/@parcel/cache/node_modules/node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "license": "MIT" - }, "node_modules/@parcel/codeframe": { "version": "2.8.3", "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.8.3.tgz", @@ -4706,6 +4634,13 @@ "@types/node": "*" } }, + "node_modules/@types/lodash": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -4725,11 +4660,12 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.14.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.5.tgz", - "integrity": "sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==", + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.21.0" } }, "node_modules/@types/parse-json": { @@ -4743,9 +4679,10 @@ "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==" }, "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" }, "node_modules/@types/reach__router": { "version": "1.3.15", @@ -4757,14 +4694,41 @@ } }, "node_modules/@types/react": { - "version": "18.3.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", - "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "version": "18.3.31", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", + "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "license": "MIT", "dependencies": { "@types/prop-types": "*", - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@types/react-helmet": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-6.1.11.tgz", + "integrity": "sha512-0QcdGLddTERotCXo3VFlUSWO3ztraw8nZ6e3zJSgG7apwV5xt+pJUS8ewPBqT4NYB1optGLprNQzFleIY84u/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react/node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, "node_modules/@types/responselike": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", @@ -4810,6 +4774,346 @@ "integrity": "sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==", "license": "MIT" }, + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -5914,12 +6218,15 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.9.7", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.7.tgz", - "integrity": "sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg==", + "version": "2.10.43", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.43.tgz", + "integrity": "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==", "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/better-opn": { @@ -6404,9 +6711,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001760", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz", - "integrity": "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==", + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", "funding": [ { "type": "opencollective", @@ -11077,9 +11384,9 @@ } }, "node_modules/gatsby-core-utils": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/gatsby-core-utils/-/gatsby-core-utils-4.15.0.tgz", - "integrity": "sha512-fxzHbCvQm1u74DSjy7G4PVqEcWb7sOCFg3kFFVUqVKe3hDCm6s1M/gRSvpm3/3fm74HhgLsmQ54Qaf54Ckyn9w==", + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/gatsby-core-utils/-/gatsby-core-utils-4.16.0.tgz", + "integrity": "sha512-QCZ9BmQp3YyYxH0Wf4bofayL3vJnayqSvsBUAhKXGh/Os0fn1KMNyAjPLnW+zrGFQaK05Vjdlp99I/Wnc3M33A==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.13", @@ -11100,7 +11407,7 @@ "xdg-basedir": "^4.0.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=18.0.0 <26" } }, "node_modules/gatsby-graphiql-explorer": { @@ -11199,29 +11506,28 @@ "@parcel/core": "^2.0.0" } }, - "node_modules/gatsby-plugin-google-analytics": { - "version": "5.13.1", - "resolved": "https://registry.npmjs.org/gatsby-plugin-google-analytics/-/gatsby-plugin-google-analytics-5.13.1.tgz", - "integrity": "sha512-6TzvUPW7CBpfpSIqpcvaRwRKTYgM3CKqSnfyRIY16vlAKYkAtZLXm3PkIbg0+mM+WzY6GRnAoeXqRkXJv0FK9A==", + "node_modules/gatsby-plugin-feed": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/gatsby-plugin-feed/-/gatsby-plugin-feed-5.16.0.tgz", + "integrity": "sha512-oKRmIbZjUS6TRRZJVP3n79jlqY5B99n4ovLxOrdrkWobmyGpIxUBRwUcIx8mrKz/7k9wxci3cdbn7pY9K18p9A==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.13", - "minimatch": "^3.1.2", - "web-vitals": "^1.1.2" + "common-tags": "^1.8.2", + "fs-extra": "^11.2.0", + "gatsby-plugin-utils": "^4.16.0", + "lodash.merge": "^4.6.2", + "rss": "^1.2.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=18.0.0 <26" }, "peerDependencies": { "gatsby": "^5.0.0-next", - "react": "^18.0.0 || ^0.0.0", - "react-dom": "^18.0.0 || ^0.0.0" + "react": "^18.0.0 || ^19.0.0 || ^0.0.0", + "react-dom": "^18.0.0 || ^19.0.0 || ^0.0.0" } }, - "node_modules/gatsby-plugin-google-fonts": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gatsby-plugin-google-fonts/-/gatsby-plugin-google-fonts-1.0.1.tgz", - "integrity": "sha512-p1NVkn27GUnDA5qHM+Z4cCcLCJIardzZXMon3640sT4xuL/AZJbsx3HEt2KY/5oZu0UXIkytkxzV2Da4rQeUIg==" - }, "node_modules/gatsby-plugin-image": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/gatsby-plugin-image/-/gatsby-plugin-image-3.15.0.tgz", @@ -11465,23 +11771,23 @@ } }, "node_modules/gatsby-plugin-utils": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/gatsby-plugin-utils/-/gatsby-plugin-utils-4.15.0.tgz", - "integrity": "sha512-6syfcye5eVYHXAU48G83mU2uXohxM3fO0BSGYYvGYlnM7FSV5HvwfFuksh3QEd0MKpE9gcQMVPvxa0pq2/PWdg==", + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/gatsby-plugin-utils/-/gatsby-plugin-utils-4.16.0.tgz", + "integrity": "sha512-5a2ui0XQBNP8vln/UyfaGBYrVpZ0oeK3fY6LjL2zx9H6wVcO5HLdjmU9yDUwQJygi2GtYW7VGQVKHfBGXMHI6A==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.13", "fastq": "^1.16.0", "fs-extra": "^11.2.0", - "gatsby-core-utils": "^4.15.0", - "gatsby-sharp": "^1.15.0", + "gatsby-core-utils": "^4.16.0", + "gatsby-sharp": "^1.16.0", "graphql-compose": "^9.0.10", "import-from": "^4.0.0", "joi": "^17.11.0", "mime": "^3.0.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=18.0.0 <26" }, "peerDependencies": { "gatsby": "^5.0.0-next", @@ -11677,15 +11983,15 @@ } }, "node_modules/gatsby-sharp": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/gatsby-sharp/-/gatsby-sharp-1.15.0.tgz", - "integrity": "sha512-nl+dSQwXPmhkE0qcLVvkLdE8scQALYopuk25RkLCDfi1VTNz0g6wcZwkmbcNjlTCR4RkbvCt7MGgNC7CVH3Ddw==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/gatsby-sharp/-/gatsby-sharp-1.16.0.tgz", + "integrity": "sha512-Xh2MwKtr9UYQnhlv5xpLXADRG6j/9dPgTLf010jNKQmvPsETkwZ3TZwnOpIgbGYJjg50rYzSCQ9RAuYXlqLmMA==", "license": "MIT", "dependencies": { "sharp": "^0.32.6" }, "engines": { - "node": ">=18.0.0" + "node": ">=18.0.0 <26" } }, "node_modules/gatsby-source-filesystem": { @@ -14680,30 +14986,35 @@ "integrity": "sha512-kmsGcmpvjStZ0ATjuHycBujtNnXiZR28BTivEu0gAMDTT7GEyodcK6zSRtu6xsrdorrPZEIN380x7BD7xEYkew==" }, "node_modules/lmdb": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.5.3.tgz", - "integrity": "sha512-iBA0cb13CobBSoGJLfZgnrykLlfJipDAnvtf+YwIqqzBEsTeQYsXrHaSBkaHd5wCWeabwrNvhjZoFMUrlo+eLw==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.9.4.tgz", + "integrity": "sha512-Kri5TSKgpLk5q1VO7vYCcqAMyXTxmis6Et+6UARkU7ygvg3ZxUX2oEu/UwBkBskaS1d73effiBrTiHYyDppcBg==", "hasInstallScript": true, + "license": "MIT", "dependencies": { - "msgpackr": "^1.5.4", - "node-addon-api": "^4.3.0", - "node-gyp-build-optional-packages": "5.0.3", - "ordered-binary": "^1.2.4", + "msgpackr": "^1.9.9", + "node-addon-api": "^6.1.0", + "node-gyp-build-optional-packages": "5.1.1", + "ordered-binary": "^1.4.1", "weak-lru-cache": "^1.2.2" }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, "optionalDependencies": { - "@lmdb/lmdb-darwin-arm64": "2.5.3", - "@lmdb/lmdb-darwin-x64": "2.5.3", - "@lmdb/lmdb-linux-arm": "2.5.3", - "@lmdb/lmdb-linux-arm64": "2.5.3", - "@lmdb/lmdb-linux-x64": "2.5.3", - "@lmdb/lmdb-win32-x64": "2.5.3" + "@lmdb/lmdb-darwin-arm64": "2.9.4", + "@lmdb/lmdb-darwin-x64": "2.9.4", + "@lmdb/lmdb-linux-arm": "2.9.4", + "@lmdb/lmdb-linux-arm64": "2.9.4", + "@lmdb/lmdb-linux-x64": "2.9.4", + "@lmdb/lmdb-win32-x64": "2.9.4" } }, "node_modules/lmdb/node_modules/node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "license": "MIT" }, "node_modules/loader-runner": { "version": "4.3.0", @@ -17628,9 +17939,10 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/msgpackr": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.10.2.tgz", - "integrity": "sha512-L60rsPynBvNE+8BWipKKZ9jHcSGbtyJYIwjRq0VrIvQ08cRjntGXJYW/tmciZ2IHWIY8WEW32Qa2xbh5+SKBZA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.12.1.tgz", + "integrity": "sha512-4EUH9tQHnMmEgzW/MdAP0KIfa1T9AF+htl0ffe2n5vb2EKn9y2co8ccpgWko6S52Jy1PQZKwRnx5/KkYjtd9MQ==", + "license": "MIT", "optionalDependencies": { "msgpackr-extract": "^3.0.2" } @@ -17865,15 +18177,28 @@ } }, "node_modules/node-gyp-build-optional-packages": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz", - "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz", + "integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.1" + }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, + "node_modules/node-gyp-build-optional-packages/node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/node-html-parser": { "version": "5.4.2", "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-5.4.2.tgz", @@ -18374,9 +18699,10 @@ } }, "node_modules/ordered-binary": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", - "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==" + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.6.1.tgz", + "integrity": "sha512-QkCdPooczexPLiXIrbVOPYkR3VO3T6v2OyKRkR1Xbhpy7/LAVXwahnRCgRp78Oe/Ehf0C/HATAxfSr6eA1oX+w==", + "license": "MIT" }, "node_modules/os-tmpdir": { "version": "1.0.2", @@ -21326,6 +21652,37 @@ "url": "https://opencollective.com/express" } }, + "node_modules/rss": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/rss/-/rss-1.2.2.tgz", + "integrity": "sha512-xUhRTgslHeCBeHAqaWSbOYTydN2f0tAzNXvzh3stjz7QDhQMzdgHf3pfgNIngeytQflrFPfy6axHilTETr6gDg==", + "license": "MIT", + "dependencies": { + "mime-types": "2.1.13", + "xml": "1.0.1" + } + }, + "node_modules/rss/node_modules/mime-db": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz", + "integrity": "sha512-5k547tI4Cy+Lddr/hdjNbBEWBwSl8EBc5aSdKvedav8DReADgWJzcYiktaRIw3GtGC1jjwldXtTzvqJZmtvC7w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rss/node_modules/mime-types": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz", + "integrity": "sha512-ryBDp1Z/6X90UvjUK3RksH0IBPM137T7cmg4OgD5wQBojlAiUwuok0QeELkim/72EtcYuNlmbkrcGuxj3Kl0YQ==", + "license": "MIT", + "dependencies": { + "mime-db": "~1.25.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -22974,9 +23331,16 @@ } }, "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } }, "node_modules/trim-lines": { "version": "3.0.1", @@ -23207,6 +23571,41 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc" + }, + "engines": { + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" + } + }, "node_modules/ua-parser-js": { "version": "1.0.38", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.38.tgz", @@ -23286,9 +23685,10 @@ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" }, "node_modules/unherit": { "version": "1.1.3", @@ -23842,11 +24242,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/web-vitals": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-1.1.2.tgz", - "integrity": "sha512-PFMKIY+bRSXlMxVAQ+m2aw9c/ioUYfDgrYot0YUa+/xa0sakubWhSDyxAKwzymvXVdF4CZI71g06W+mqhzu6ig==" - }, "node_modules/webdav-server": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/webdav-server/-/webdav-server-2.6.2.tgz", @@ -23862,9 +24257,13 @@ } }, "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } }, "node_modules/webpack": { "version": "5.98.0", @@ -23985,12 +24384,17 @@ } }, "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-17.1.0.tgz", + "integrity": "sha512-3GeworPmc2ZfEEHP7lEbUfBX/L75wdEsi0rLNhXcXxnoN5jyq0SL5gCy06SGW2cyTIZdTvWIDQNQoza++vKeaw==", + "license": "MIT", "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "@exodus/bytes": "^1.15.1", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^22.14.0 || >=24.0.0" } }, "node_modules/which": { @@ -24219,6 +24623,12 @@ "node": ">=8" } }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "license": "MIT" + }, "node_modules/xml-js": { "version": "1.6.11", "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", diff --git a/package.json b/package.json index b73c30c..0e40df8 100644 --- a/package.json +++ b/package.json @@ -14,16 +14,18 @@ "serve": "gatsby serve", "clean": "gatsby clean", "lint": "npx prettier --check \"src/**/*.+(ts|tsx|js|jsx|json|css|scss)\"", - "lint:fix": "npx prettier --write \"src/**/*.+(ts|tsx|js|jsx|json|css|scss)\" --ignore-path .gitignore" + "lint:fix": "npx prettier --write \"src/**/*.+(ts|tsx|js|jsx|json|css|scss)\" --ignore-path .gitignore", + "typecheck": "tsc --noEmit" }, "dependencies": { "@browniebroke/gatsby-image-gallery": "^8.2.0", "@mdx-js/mdx": "^3.1.1", "@mdx-js/react": "^3.1.1", "babel-plugin-styled-components": "^2.1.4", + "baseline-browser-mapping": "^2.10.43", + "caniuse-lite": "^1.0.30001806", "gatsby": "^5.15.0", - "gatsby-plugin-google-analytics": "^5.13.1", - "gatsby-plugin-google-fonts": "^1.0.1", + "gatsby-plugin-feed": "^5.16.0", "gatsby-plugin-image": "^3.15.0", "gatsby-plugin-local-search": "^2.0.1", "gatsby-plugin-manifest": "^5.15.0", @@ -50,8 +52,30 @@ }, "devDependencies": { "@popperjs/core": "^2.9.2", + "@types/lodash": "^4.17.24", + "@types/node": "^20.19.43", + "@types/react": "^18.3.31", + "@types/react-dom": "^18.3.7", + "@types/react-helmet": "^6.1.11", "bootstrap": "^5.0.0-beta3", "cloudron-surfer": "^6.4.1", - "jquery": "^3.6.0" + "jquery": "^3.6.0", + "typescript": "^7.0.2" + }, + "allowScripts": { + "lmdb@2.5.2": true, + "lmdb@2.5.3": true, + "msgpackr@1.10.2": true, + "@parcel/watcher@2.5.1": true + }, + "overrides": { + "msgpackr": "^1.12.1", + "lmdb": "^2.9.4", + "ordered-binary": "^1.6.1", + "whatwg-url": "^17.1.0" + }, + "engines": { + "node": ">=24.0.0", + "npm": ">=10.0.0" } } diff --git a/src/components/footer/index.tsx b/src/components/footer/index.tsx index 79b0dfb..6bfb4a4 100644 --- a/src/components/footer/index.tsx +++ b/src/components/footer/index.tsx @@ -1,7 +1,11 @@ import React from 'react' +import { FaRss } from 'react-icons/fa' import { Section } from '../shared' import { SolidButton } from '../shared/styledComponents' import { StyledHeading, StyledDesc, InputStyled, StyledAnchor } from './style' +import { siteMetadata } from '../../../gatsby-config' + +const rssFeedUrl = `${siteMetadata.siteUrl}rss.xml` const anchorStyles = { color: '#888' @@ -13,42 +17,39 @@ const Footer = () => (
Data Controller - Data Controller is the product of a UK company with a singular focus on{' '} - - SAS Web Apps - . + Data Controller is the product of a UK company with a singular focus + on SAS Web Apps + .
Source Code - All our source code can be found on our self-hosted{' '} - + Data Controller source is on our self-hosted{' '} + Gitea Repository - . + ; the underlying SASjs framework is on{' '} + GitHub.
Other Resources - Leverage our underlying tech stack on{' '} - - Github + Connect on{' '} + + LinkedIn + + , read the{' '} + + docs + + , or subscribe to the{' '} + + + RSS feed {' '} - and build your own SAS Powered Web Apps. + for updates.
diff --git a/src/components/footer/style.js b/src/components/footer/style.tsx similarity index 79% rename from src/components/footer/style.js rename to src/components/footer/style.tsx index 36c76ba..581af3f 100644 --- a/src/components/footer/style.js +++ b/src/components/footer/style.tsx @@ -1,6 +1,8 @@ -import React from 'react' +import * as React from 'react' import styled from 'styled-components' +import type { StyledAnchorProps } from '../../types' + export const StyledHeading = styled.h6` margin-bottom: 0.8rem; text-transform: uppercase; @@ -33,7 +35,10 @@ const Anchor = styled.a` } ` -export const StyledAnchor = ({ children, href }) => ( +export const StyledAnchor: React.FC = ({ + children, + href +}) => ( {children} diff --git a/src/components/herosection/index.tsx b/src/components/herosection/index.tsx index addbab0..0bef502 100644 --- a/src/components/herosection/index.tsx +++ b/src/components/herosection/index.tsx @@ -1,21 +1,15 @@ import React from 'react' -import { PageProps, Link } from 'gatsby' - -import styled from 'styled-components' +import { Link } from 'gatsby' import { Hero, HeroHeading, HeroDesc } from './style' import { BottomSectionArrow, OutlineButton } from '../shared/styledComponents' import { Container } from '../shared' -import { pathPrefix } from '../../../gatsby-config.js' +import { pathPrefix } from '../../../gatsby-config' -type DataProps = { - location: Location - heading: string - desc: string -} +import type { HeroSectionProps } from '../../types' -const HeroSection: React.FC> = ({ +const HeroSection: React.FC = ({ location, heading, desc diff --git a/src/components/herosection/style.js b/src/components/herosection/style.tsx similarity index 78% rename from src/components/herosection/style.js rename to src/components/herosection/style.tsx index 033e255..203f679 100644 --- a/src/components/herosection/style.js +++ b/src/components/herosection/style.tsx @@ -1,7 +1,7 @@ import styled from 'styled-components' import background from '../../images/home_hero_bg.png' -export const Hero = styled.main` +export const Hero = styled.main<{ bg?: boolean }>` position: relative; padding: 50px 0; color: white; @@ -13,7 +13,8 @@ export const Hero = styled.main` ` export const HeroHeading = styled.h1` - font-family: 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, + font-family: + 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif; text-transform: uppercase; ` diff --git a/src/components/layout.tsx b/src/components/layout.tsx index 3f9f3fc..6944a0c 100644 --- a/src/components/layout.tsx +++ b/src/components/layout.tsx @@ -1,16 +1,12 @@ import React, { useEffect } from 'react' -import { PageProps } from 'gatsby' import Navibar from './navibar' import HeroSection from './herosection' import Footer from './footer' -type DataProps = { - children?: React.ReactNode - heroSection: boolean -} +import type { LayoutProps } from '../types' -const Layout: React.FC> = ({ +const Layout: React.FC = ({ location, children, heroSection = true, diff --git a/src/components/navibar/index.tsx b/src/components/navibar/index.tsx index 21c4a67..d99fcae 100644 --- a/src/components/navibar/index.tsx +++ b/src/components/navibar/index.tsx @@ -1,49 +1,34 @@ import React from 'react' -import { Link, PageProps } from 'gatsby' +import { Link } from 'gatsby' import dcLogo from '../../images/dclogo.png' import { Container } from '../shared' import { logoStyles, CustomNavBar, ulStyles, Li, StyledLink } from './style' -import { pathPrefix } from '../../../gatsby-config.js' +import { pathPrefix } from '../../../gatsby-config' -const naviLinks = [ - { - name: 'Home', - url: '/', - active: 'no' - }, - { - name: 'About', - url: '/about/', - active: 'no' - }, - { - name: 'Blog', - url: '/blog/', - active: 'no' - }, - { - name: 'FAQ', - url: '/faq/', - active: 'no' - }, +import type { NavibarProps } from '../../types' + +interface NaviLink { + name: string + url: string + active: 'yes' | 'no' +} + +const naviLinks: NaviLink[] = [ + { name: 'Home', url: '/', active: 'no' }, + { name: 'About', url: '/about/', active: 'no' }, + { name: 'Blog', url: '/blog/', active: 'no' }, + { name: 'Feed', url: '/feed/', active: 'no' }, + { name: 'FAQ', url: '/faq/', active: 'no' }, { name: 'Documentation', url: 'https://docs.datacontroller.io/', active: 'no' }, - { - name: 'Pricing', - url: '/pricing/', - active: 'no' - }, - { - name: 'Book Demo', - url: '/contact/', - active: 'no' - }, + { name: 'Pricing', url: '/pricing/', active: 'no' }, + { name: 'Book Demo', url: '/contact/', active: 'no' }, { name: 'Source Code', url: 'https://git.datacontroller.io/dc/dc', @@ -51,11 +36,7 @@ const naviLinks = [ } ] -type DataProps = { - location: Location -} - -const Navibar: React.FC> = ({ location }) => { +const Navibar: React.FC = ({ location }) => { naviLinks.forEach((link) => (link.active = 'no')) const currentLink = naviLinks.find( (link) => pathPrefix + link.url === location?.pathname diff --git a/src/components/navibar/style.js b/src/components/navibar/style.tsx similarity index 97% rename from src/components/navibar/style.js rename to src/components/navibar/style.tsx index 76ef0fb..617dba3 100644 --- a/src/components/navibar/style.js +++ b/src/components/navibar/style.tsx @@ -1,8 +1,7 @@ -import React from 'react' +import * as React from 'react' import styled, { css } from 'styled-components' import { Link } from 'gatsby' -// styles export const logoStyles = { height: '55px' } @@ -295,7 +294,6 @@ const LinkUnderlineStyles = css` transition: opacity 0.3s ease; ` -// styled components export const Li = styled.li` position: relative; @media (min-width: 992px) { @@ -315,7 +313,14 @@ export const Li = styled.li` } } ` -export const StyledLink = styled((props) => )` + +interface StyledLinkProps { + active?: string +} + +export const StyledLink = styled(({ active, ...rest }: any) => ( + +))` padding-right: 0.8rem !important; padding-left: 0.8rem !important; color: white !important; diff --git a/src/components/seo.tsx b/src/components/seo.tsx index ae40469..4dd6721 100644 --- a/src/components/seo.tsx +++ b/src/components/seo.tsx @@ -1,9 +1,16 @@ import * as React from 'react' -import PropTypes from 'prop-types' import { Helmet } from 'react-helmet' import { useStaticQuery, graphql } from 'gatsby' -const Seo = ({ description, lang, meta, title, previewImg = undefined }) => { +import type { SeoProps } from '../types' + +const Seo: React.FC = ({ + description = '', + lang = 'en', + meta = [], + title = '', + previewImg +}) => { const { site } = useStaticQuery(graphql` query { site { @@ -37,44 +44,36 @@ const Seo = ({ description, lang, meta, title, previewImg = undefined }) => { lang }} title={pageTitle} - meta={[ - { name: 'author', property: 'author', content: author }, + link={[ { - name: 'description', - property: 'og:description', - content: metaDescription - }, - // { name: 'facebook:site', content: '', }, - { name: 'image', property: 'og:image', content: image }, - { - name: `linkedin:site`, - content: site.siteMetadata?.social?.linkedin || `` - }, - { name: `twitter:card`, content: `summary` }, - // { name: `twitter:creator`, content: site.siteMetadata?.social?.twitter || `` }, - { name: `twitter:description`, content: metaDescription }, - // { name: 'twitter:site', content: `${site?.twitter}`, }, - { name: `twitter:title`, content: title }, - // { name: 'youtube:site', content: `${site?.youtube}`, }, - { property: `og:title`, content: title }, - { property: `og:type`, content: `website` } - ].concat(meta)} + rel: 'alternate', + type: 'application/rss+xml', + title: `${defaultTitle} RSS Feed`, + href: `${siteUrl}rss.xml` + } + ]} + meta={( + [ + { name: 'author', property: 'author', content: author }, + { + name: 'description', + property: 'og:description', + content: metaDescription + }, + { name: 'image', property: 'og:image', content: image }, + { + name: `linkedin:site`, + content: site.siteMetadata?.social?.linkedin || `` + }, + { name: `twitter:card`, content: `summary` }, + { name: `twitter:description`, content: metaDescription }, + { name: `twitter:title`, content: title }, + { property: `og:title`, content: title }, + { property: `og:type`, content: `website` } + ] as Array<{ name?: string; property?: string; content?: string }> + ).concat(meta)} /> ) } -Seo.defaultProps = { - lang: `en`, - meta: [], - description: ``, - title: `` -} - -Seo.propTypes = { - description: PropTypes.string, - lang: PropTypes.string, - meta: PropTypes.arrayOf(PropTypes.object), - title: PropTypes.string -} - export default Seo diff --git a/src/components/shared/container.tsx b/src/components/shared/container.tsx index 61f98c7..d209e68 100644 --- a/src/components/shared/container.tsx +++ b/src/components/shared/container.tsx @@ -1,10 +1,7 @@ -import React from 'react' +import * as React from 'react' import styled from 'styled-components' -import { PageProps } from 'gatsby' -type DataProps = { - children?: React.ReactNode -} +import type { ContainerProps } from '../../types' const StyledDiv = styled.div` @media (min-width: 576px) { @@ -13,6 +10,6 @@ const StyledDiv = styled.div` } ` -export const Container: React.FC> = ({ children }) => { +export const Container: React.FC = ({ children }) => { return {children} } diff --git a/src/components/shared/scheduleDemo.tsx b/src/components/shared/scheduleDemo.tsx index 06f43f3..fa7f9ff 100644 --- a/src/components/shared/scheduleDemo.tsx +++ b/src/components/shared/scheduleDemo.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components' import { FaEnvelope } from 'react-icons/fa' -export const StyledLink = styled((props) => )` +export const StyledLink = styled(Link)` color: rgb(255, 255, 255); background-color: rgb(144, 196, 69); border-radius: 0px; diff --git a/src/components/shared/section.tsx b/src/components/shared/section.tsx index 9284755..0da0919 100644 --- a/src/components/shared/section.tsx +++ b/src/components/shared/section.tsx @@ -1,25 +1,19 @@ -import React from 'react' +import * as React from 'react' import styled from 'styled-components' -import { PageProps } from 'gatsby' import { BottomSectionArrow } from './styledComponents' import { Container } from './' -type DataProps = { - children?: React.ReactNode - color?: string - bgColor?: string - bottomArrow?: boolean -} +import type { SectionProps } from '../../types' -const StyledSection = styled.div` +const StyledSection = styled.div<{ color?: string; bgColor?: string }>` position: relative; padding: 50px 0; color: ${(props) => props.color || 'white'}; background-color: ${(props) => props.bgColor || '#314351'}; ` -export const Section: React.FC> = ({ +export const Section: React.FC = ({ children, bgColor, color, diff --git a/src/components/shared/styledComponents.js b/src/components/shared/styledComponents.tsx similarity index 76% rename from src/components/shared/styledComponents.js rename to src/components/shared/styledComponents.tsx index cb2adc4..4b78e3a 100644 --- a/src/components/shared/styledComponents.js +++ b/src/components/shared/styledComponents.tsx @@ -1,6 +1,8 @@ -import React from 'react' +import * as React from 'react' import styled from 'styled-components' +import type { SolidButtonProps, OutlineButtonProps } from '../../types' + const BottomArrow = styled.div` width: 50px; height: 50px; @@ -9,9 +11,6 @@ const BottomArrow = styled.div` background: inherit; transform: translateX(-50%) rotate(45deg); left: 50%; - // right: 0; - // margin-left: auto; - // margin-right: auto; z-index: 10; ` const BottomArrowWrapper = styled.div` @@ -29,16 +28,17 @@ export const BottomSectionArrow = () => ( ) -export const SectionHeading = styled.h2` +export const SectionHeading = styled.h2<{ center?: string }>` text-align: ${(props) => (props.center === 'no' ? 'left' : 'center')}; letter-spacing: 1px; font-weight: 400; - font-family: 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, + font-family: + 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif; text-transform: uppercase; ` -export const SectionDesc = styled.p` +export const SectionDesc = styled.p<{ center?: string; opacity?: string }>` text-align: ${(props) => (props.center === 'no' ? 'left' : 'center')}; opacity: ${(props) => props.opacity ?? 0.6}; a { @@ -59,12 +59,12 @@ const StyledSolidButton = styled.button` } ` -export const SolidButton = ({ +export const SolidButton: React.FC = ({ children, theme = 'light', type = 'submit', disabled = false, - onClick = undefined + onClick }) => ( ( +export const OutlineButton: React.FC = ({ children }) => ( {children} diff --git a/src/controllers/NostrController.ts b/src/controllers/NostrController.ts index 678adf8..41273ed 100644 --- a/src/controllers/NostrController.ts +++ b/src/controllers/NostrController.ts @@ -34,7 +34,7 @@ export class NostrController extends EventEmitter { /** * Function will publish provided event to the provided relays */ - publishEvent = async (event: Event, relays: string[]) => { + publishEvent = async (event: Event, relays: string[]): Promise => { const simplePool = new SimplePool() const promises = simplePool.publish(relays, event) @@ -47,7 +47,7 @@ export class NostrController extends EventEmitter { }) if (publishedRelays.length === 0) { - const failedPublishes: any[] = [] + const failedPublishes: Array<{ relay: string; error: string }> = [] const fallbackRejectionReason = 'Attempt to publish an event has been rejected with unknown reason.' @@ -92,7 +92,7 @@ export class NostrController extends EventEmitter { return Promise.resolve(signedEvent) } - nip04Encrypt = async (receiver: string, content: string) => { + nip04Encrypt = async (receiver: string, content: string): Promise => { if (!this.generatedKeys) { throw new Error(`Private & public key pair is not found.`) } @@ -113,7 +113,7 @@ export class NostrController extends EventEmitter { * @param isSigner Boolean indicating whether the recipient is a signer or viewer. * @param setAuthUrl Function to set the authentication URL in the component state. */ - sendDM = async (pubkey: string, message: string) => { + sendDM = async (pubkey: string, message: string): Promise => { // Set up timeout promise to handle encryption timeout const timeoutPromise = new Promise((_, reject) => { setTimeout(() => { @@ -159,7 +159,7 @@ export class NostrController extends EventEmitter { * @param hexKey hex private or public key * @returns whether or not is key valid */ - validateHex = (hexKey: string) => { + validateHex = (hexKey: string): RegExpMatchArray | null => { return hexKey.match(/^[a-f0-9]{64}$/) } @@ -193,7 +193,7 @@ export class NostrController extends EventEmitter { return { private: nip19.nsecEncode(nsec), public: getPublicKey(nsec) } } - verifySignedEvent = (event: SignedEvent) => { + verifySignedEvent = (event: SignedEvent): void => { const isGood = verifyEvent(event) if (!isGood) { diff --git a/src/pages/404.tsx b/src/pages/404.tsx index 95c1ffb..1b37f53 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -1,5 +1,4 @@ -import React from 'react' -// import { Link } from 'gatsby' +import * as React from 'react' import Layout from '../components/layout' import Seo from '../components/seo' @@ -7,7 +6,13 @@ import Seo from '../components/seo' import { Section } from '../components/shared' import { SideBar } from '../templates/sidebar' -const NotFound = ({ data, location, pageContext }) => ( +import type { PageProps } from 'gatsby' +import type { PageContext } from '../types' + +const NotFound: React.FC> = ({ + location, + pageContext +}) => (
diff --git a/src/pages/about.tsx b/src/pages/about.tsx index a377a74..99d0769 100644 --- a/src/pages/about.tsx +++ b/src/pages/about.tsx @@ -1,5 +1,5 @@ -import { PageProps, Link, graphql } from 'gatsby' -import React from 'react' +import { PageProps, Link } from 'gatsby' +import * as React from 'react' import Layout from '../components/layout' import Seo from '../components/seo' @@ -10,17 +10,7 @@ import { SectionDesc } from '../components/shared/styledComponents' -type DataProps = { - site: { - meta: { - title: string - description: string - social: { linkedin: string } - } - } -} - -const About: React.FC> = ({ data, location }) => { +const About: React.FC> = ({ location }) => { return ( > = ({ data, location }) => { +const Contact: React.FC> = ({ location }) => { const nostrController = NostrController.getInstance() - const [name, setName] = useState() - const [email, setEmail] = useState() - const [emailError, setEmailError] = useState(false) - const [subject, setSubject] = useState() - const [message, setMessage] = useState() - const [notification, setNotification] = useState() + const [name, setName] = React.useState() + const [email, setEmail] = React.useState() + const [emailError, setEmailError] = React.useState(false) + const [subject, setSubject] = React.useState() + const [message, setMessage] = React.useState() + const [notification, setNotification] = React.useState() const handleEmailChange = (e: React.ChangeEvent) => { const value = e.target.value @@ -98,7 +88,7 @@ Email: ${email} Subject: ${subject} Message: ${message}` ) - .catch((err) => { + .catch((err: unknown) => { setNotification( `Something went wrong. Please check the console for more information. Please try one more time.` ) @@ -176,7 +166,7 @@ Message: ${message}` className="form-control contactFormStyles" id="mesage" name="message" - rows="5" + rows={5} rules="required|max:200" onChange={(evt) => { setMessage(evt.target.value) diff --git a/src/pages/faq.tsx b/src/pages/faq.tsx index c289d1f..a3116a7 100644 --- a/src/pages/faq.tsx +++ b/src/pages/faq.tsx @@ -1,5 +1,5 @@ -import { PageProps, Link, graphql } from 'gatsby' -import React from 'react' +import { PageProps, Link } from 'gatsby' +import * as React from 'react' import Layout from '../components/layout' import Seo from '../components/seo' @@ -13,17 +13,7 @@ import { import { FAQ } from '../styledComponents/faq' -type DataProps = { - site: { - meta: { - title: string - description: string - social: { linkedin: string } - } - } -} - -const Faq: React.FC> = ({ data, location }) => { +const Faq: React.FC> = ({ location }) => { return ( = ({ data, location }) => { +const CustomWrapper: React.FC<{ + children?: React.ReactNode + onClick?: () => void +}> = ({ children, onClick }) => ( + {children} +) + +const Home: React.FC> = ({ data, location }) => { const images = data.images.edges.map(({ node }) => ({ ...node.childImageSharp, - // Use original name as caption. - // The `originalName` is queried in a nested field, - // but the `Gallery` component expects `caption` at the top level. - caption: node.childImageSharp.meta.originalName + caption: node.name })) return ( @@ -231,13 +231,7 @@ const Home: React.FC = ({ data, location }) => {
See How it Looks - ( - {children} - )} - /> +
@@ -254,6 +248,7 @@ export const pageQuery = graphql` ) { edges { node { + name childImageSharp { thumb: gatsbyImageData( width: 300 @@ -261,9 +256,6 @@ export const pageQuery = graphql` placeholder: BLURRED ) full: gatsbyImageData(layout: FULL_WIDTH) - meta: fixed { - originalName - } } } } diff --git a/src/pages/{MarkdownRemark.frontmatter__slug}.tsx b/src/pages/{MarkdownRemark.frontmatter__slug}.tsx index 842edb0..bc82aa0 100644 --- a/src/pages/{MarkdownRemark.frontmatter__slug}.tsx +++ b/src/pages/{MarkdownRemark.frontmatter__slug}.tsx @@ -1,5 +1,5 @@ -import React from 'react' -import { graphql } from 'gatsby' +import * as React from 'react' +import { graphql, PageProps } from 'gatsby' import styled from 'styled-components' import Layout from '../components/layout' @@ -7,6 +7,8 @@ import Seo from '../components/seo' import { Section } from '../components/shared' +import type { PostNode, PageContext } from '../types' + const StyledMarkdown = styled.div` color: rgb(102, 102, 102); h2, @@ -18,13 +20,20 @@ const StyledMarkdown = styled.div` h2 { text-transform: uppercase; letter-spacing: 1px; - font-family: 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, - Arial, sans-serif; + font-family: + 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, + sans-serif; } ` -export default function Template({ data, location }) { - const { frontmatter, html } = data?.markdownRemark +interface MarkdownPageData { + markdownRemark: PostNode +} + +const MarkdownPageTemplate: React.FC< + PageProps +> = ({ data, location }) => { + const { frontmatter, html } = data.markdownRemark return ( ({ - alt: props.info || '', - title: props.info || '' -}))` - max-width: 100%; -` diff --git a/src/styledComponents/contact.tsx b/src/styledComponents/contact.tsx new file mode 100644 index 0000000..c469f75 --- /dev/null +++ b/src/styledComponents/contact.tsx @@ -0,0 +1,20 @@ +import styled from 'styled-components' + +export const StyledHeading = styled.h3` + font-family: + 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, + sans-serif; +` + +export const StyledLabel = styled.label` + margin-bottom: 0; +` + +export const ContactBackground = styled.img.attrs<{ info?: string }>( + (props) => ({ + alt: props.info || '', + title: props.info || '' + }) +)` + max-width: 100%; +` diff --git a/src/styledComponents/faq.js b/src/styledComponents/faq.tsx similarity index 78% rename from src/styledComponents/faq.js rename to src/styledComponents/faq.tsx index 6dc879c..0ad8743 100644 --- a/src/styledComponents/faq.js +++ b/src/styledComponents/faq.tsx @@ -1,15 +1,18 @@ -import React from 'react' +import * as React from 'react' import styled from 'styled-components' import { FcFaq } from 'react-icons/fc' +import type { FaqProps } from '../types' + const StyledFaq = styled.div` margin-bottom: 20px; ` const StyledQuestion = styled.h5` color: #222; - font-family: 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, + font-family: + 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif; text-transform: uppercase; ` @@ -33,7 +36,7 @@ const FaqDetails = styled.div` margin-bottom: 20px; ` -export const FAQ = ({ question, answer }) => ( +export const FAQ: React.FC = ({ question, answer }) => ( diff --git a/src/styledComponents/index.js b/src/styledComponents/index.tsx similarity index 73% rename from src/styledComponents/index.js rename to src/styledComponents/index.tsx index df47f3c..ca1fcd1 100644 --- a/src/styledComponents/index.js +++ b/src/styledComponents/index.tsx @@ -1,6 +1,9 @@ -import React from 'react' +import * as React from 'react' import styled from 'styled-components' import { ImArrowRight } from 'react-icons/im' +import type { IconType } from 'react-icons' + +import type { ArtProps, ReasonProps, FeatureProps } from '../types' export const CenteredText = styled.p` text-align: center; @@ -9,20 +12,19 @@ export const CenteredText = styled.p` margin: 0 auto; font-size: 1.2rem; line-height: 1; - font-family: 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, + font-family: + 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif; ` -export const Art = styled.img.attrs((props) => ({ +export const Art = styled.img.attrs((props) => ({ alt: props.info || '', title: props.info || '' }))` max-width: 100%; - display: block; - margin: 0 auto; - padding: 20px; + height: auto; ` -const ArrowHolder = styled.div` +const ArrowHolder = styled.div<{ bgColor?: string }>` display: inline-block; border-radius: 50px; padding: 15px 17px; @@ -30,7 +32,7 @@ const ArrowHolder = styled.div` background-color: ${(props) => props.bgColor === 'red' ? '#ed1c1c' : '#90c445'}; ` -const RightArrow = ({ bgColor = '' }) => ( +const RightArrow: React.FC<{ bgColor?: string }> = ({ bgColor = '' }) => ( @@ -46,7 +48,7 @@ const ReasonDesc = styled.p` text-transform: uppercase; ` -export const Reason = ({ text, bgColor = '' }) => ( +export const Reason: React.FC = ({ text, bgColor = '' }) => ( <> {text} @@ -62,7 +64,7 @@ const IconHolderStyled = styled.div` vertical-align: top; ` -const IconHolder = ({ Icon }) => { +const IconHolder = ({ Icon }: { Icon: IconType }) => { return ( @@ -77,7 +79,8 @@ const FeatureDetails = styled.div` margin-bottom: 20px; ` const FeatureTitle = styled.h5` - font-family: 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, + font-family: + 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif; text-transform: uppercase; ` @@ -86,7 +89,12 @@ const FeatureDesc = styled.p` font-size: 0.9rem; ` -export const Feature = ({ title, desc, Icon, className }) => ( +export const Feature: React.FC = ({ + title, + desc, + Icon, + className +}) => (
diff --git a/src/styles/montserrat.css b/src/styles/montserrat.css new file mode 100644 index 0000000..1829bc3 --- /dev/null +++ b/src/styles/montserrat.css @@ -0,0 +1,35 @@ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url('/fonts/Montserrat-300.woff2') format('woff2'); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} + +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('/fonts/Montserrat-400.woff2') format('woff2'); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} + +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('/fonts/Montserrat-500.woff2') format('woff2'); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/src/templates/blog-list.tsx b/src/templates/blog-list.tsx index 1a3b506..d577fb7 100644 --- a/src/templates/blog-list.tsx +++ b/src/templates/blog-list.tsx @@ -1,5 +1,5 @@ -import { Link, graphql } from 'gatsby' -import React from 'react' +import { Link, graphql, PageProps } from 'gatsby' +import * as React from 'react' import kebabCase from 'lodash/kebabCase' import styled from 'styled-components' @@ -16,27 +16,39 @@ import { import Post from './postpreview' import { SideBar } from './sidebar' -const BlogListTemplate = ({ data, location, pageContext }) => { +import type { PostNode, PageContext } from '../types' + +interface BlogListData { + remark: { + posts: Array<{ post: PostNode }> + } +} + +const BlogListTemplate: React.FC> = ({ + data, + location, + pageContext +}) => { const posts = data.remark.posts - const iniPath = - pageContext.page == 'index' + const iniPath: string = + pageContext.page === 'index' ? `/blog/` - : pageContext.page == 'year' - ? `/${pageContext.year}/` - : pageContext.page == 'category' - ? `/category/${kebabCase(pageContext.tag)}/` - : null + : pageContext.page === 'year' + ? `/${pageContext.year}/` + : pageContext.page === 'category' + ? `/category/${kebabCase(pageContext.tag ?? '')}/` + : `/blog/` const pageInfo = `Page ${pageContext.currentPage} of ${pageContext.numPages}` - Array.from({ length: 5 }, (v, k) => k + 1) const paginationJSX = Array.from( - { length: pageContext.numPages }, + { length: pageContext.numPages ?? 0 }, (_, i) => i + 1 ).map((pageIndex) => { const link = pageIndex === 1 ? iniPath : `${iniPath}page/${pageIndex}` return ( {
- {posts.map((data, i) => ( - + {posts.map(({ post }, i) => ( + ))}
{paginationJSX} @@ -114,5 +126,3 @@ export const pageQuery = graphql` } } ` - -// tags diff --git a/src/templates/blog-post.tsx b/src/templates/blog-post.tsx index a20db6c..cdf336d 100644 --- a/src/templates/blog-post.tsx +++ b/src/templates/blog-post.tsx @@ -1,5 +1,5 @@ -import React from 'react' -import { Link, graphql } from 'gatsby' +import * as React from 'react' +import { graphql, PageProps } from 'gatsby' import Layout from '../components/layout' import Seo from '../components/seo' @@ -8,15 +8,19 @@ import { Section } from '../components/shared' import Post from './post' import { SideBar } from './sidebar' -const BlogPostTemplate = ({ data, location, pageContext }) => { +import type { PostNode, PageContext } from '../types' + +const BlogPostTemplate: React.FC< + PageProps<{ post: PostNode }, PageContext> +> = ({ data, location, pageContext }) => { const { post } = data const { previewImg } = post.frontmatter return ( { +import type { PageContext, PostNode, SearchPost } from '../types' + +interface SearchData { + localSearchBlog: { + index: string + store: Record + } +} + +const BlogSearchTemplate: React.FC> = ({ + location, + pageContext +}) => { const queryData = useStaticQuery(graphql` query { localSearchBlog { @@ -34,12 +44,12 @@ const BlogSearchTemplate = ({ location, pageContext }) => { query, queryData.localSearchBlog.index, queryData.localSearchBlog.store - ) - const postsJSX = [] + ) as SearchPost[] + const postsJSX: React.ReactElement[] = [] if (query) { posts.forEach((post, i) => { - const _post = { + const _post: PostNode = { id: post.id, html: post.html, fields: { @@ -48,7 +58,7 @@ const BlogSearchTemplate = ({ location, pageContext }) => { frontmatter: { title: post.title, date: post.date, - previewImg: post.previewImg + previewImg: post.previewImg as PostNode['frontmatter']['previewImg'] } } diff --git a/src/templates/feed-list.tsx b/src/templates/feed-list.tsx new file mode 100644 index 0000000..4eb2550 --- /dev/null +++ b/src/templates/feed-list.tsx @@ -0,0 +1,131 @@ +import { Link, graphql, PageProps } from 'gatsby' +import * as React from 'react' +import kebabCase from 'lodash/kebabCase' + +import Layout from '../components/layout' +import Seo from '../components/seo' + +import { Section } from '../components/shared' +import { + SectionHeading, + SectionDesc, + SolidButton +} from '../components/shared/styledComponents' + +import Post from './postpreview' +import { SideBar } from './sidebar' + +import type { PostNode, PageContext } from '../types' + +interface FeedListData { + remark: { + posts: Array<{ post: PostNode }> + } +} + +const FeedListTemplate: React.FC> = ({ + data, + location, + pageContext +}) => { + const posts = data.remark.posts + + const iniPath: string = + pageContext.page === 'index' + ? `/feed/` + : pageContext.page === 'year' + ? `/feed/${pageContext.year}/` + : pageContext.page === 'category' + ? `/feed/category/${kebabCase(pageContext.tag ?? '')}/` + : `/feed/` + + const pageInfo = `Page ${pageContext.currentPage} of ${pageContext.numPages}` + const paginationJSX = Array.from( + { length: pageContext.numPages ?? 0 }, + (_, i) => i + 1 + ).map((pageIndex) => { + const link = pageIndex === 1 ? iniPath : `${iniPath}page/${pageIndex}` + return ( + + {pageIndex} + + ) + }) + return ( + + +
+
+
+
+ {posts.map(({ post }, i) => ( + + ))} +
+ {paginationJSX} + {pageInfo} +
+
+ +
+
+
+
+ ) +} + +export default FeedListTemplate + +export const pageQuery = graphql` + query FeedListQuery( + $filter: MarkdownRemarkFilterInput! + $skip: Int! + $limit: Int! + ) { + remark: allMarkdownRemark( + filter: $filter + limit: $limit + skip: $skip + sort: { frontmatter: { date: DESC } } + ) { + posts: edges { + post: node { + html + fields { + slug + } + frontmatter { + title + date(formatString: "MMMM DD, YYYY") + author + authorLink + previewImg { + childImageSharp { + gatsbyImageData(layout: CONSTRAINED) + } + } + } + } + } + } + } +` diff --git a/src/templates/feed-post.tsx b/src/templates/feed-post.tsx new file mode 100644 index 0000000..cfc414b --- /dev/null +++ b/src/templates/feed-post.tsx @@ -0,0 +1,71 @@ +import * as React from 'react' +import { graphql, PageProps } from 'gatsby' + +import Layout from '../components/layout' +import Seo from '../components/seo' + +import { Section } from '../components/shared' +import Post from './post' +import { SideBar } from './sidebar' + +import type { PostNode, PageContext } from '../types' + +const FeedPostTemplate: React.FC< + PageProps<{ post: PostNode }, PageContext> +> = ({ data, location, pageContext }) => { + const { post } = data + const { previewImg } = post.frontmatter + + return ( + + +
+
+
+ +
+
+ +
+
+
+
+ ) +} + +export default FeedPostTemplate + +export const pageQuery = graphql` + query FeedPostByPath($id: String!) { + post: markdownRemark(id: { eq: $id }) { + id + html + fields { + slug + } + frontmatter { + title + description + date(formatString: "MMMM DD, YYYY") + author + authorLink + previewImg { + childImageSharp { + gatsbyImageData(layout: CONSTRAINED) + } + } + tags + } + } + } +` diff --git a/src/templates/post/index.tsx b/src/templates/post/index.tsx index 7e5d7b9..aac7291 100644 --- a/src/templates/post/index.tsx +++ b/src/templates/post/index.tsx @@ -1,12 +1,14 @@ -import React from 'react' +import * as React from 'react' import { Link } from 'gatsby' import kebabCase from 'lodash/kebabCase' -import { GatsbyImage } from 'gatsby-plugin-image' +import { GatsbyImage, IGatsbyImageData } from 'gatsby-plugin-image' import styled from 'styled-components' -export const StyledLink = styled((props) => )` +import type { PostNode } from '../../types' + +export const StyledLink = styled(Link)` text-decoration: none; color: black; &:hover { @@ -16,7 +18,8 @@ export const StyledLink = styled((props) => )` ` const StyledTitle = styled.h5` - font-family: 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, + font-family: + 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif; margin-bottom: 0; ` @@ -45,7 +48,8 @@ const StyledContent = styled.div` padding: 15px 0; color: #666666; - font-family: 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, + font-family: + 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif; a { color: black; @@ -116,7 +120,12 @@ const StyledContent = styled.div` } ` -const Post = ({ post, location }) => { +interface PostProps { + post: PostNode + location?: Location +} + +const Post: React.FC = ({ post }) => { const tagsJSX = (post.frontmatter?.tags || []).map((tag, index) => ( {index > 0 && ', '} @@ -134,14 +143,18 @@ const Post = ({ post, location }) => { ) : ( {post.frontmatter.author} ) + const previewImgData = post.frontmatter.previewImg?.childImageSharp + ?.gatsbyImageData as IGatsbyImageData | undefined return (
- + {previewImgData && ( + + )} {post.frontmatter.title} diff --git a/src/templates/postpreview/index.tsx b/src/templates/postpreview/index.tsx index e7be9a1..d0748bf 100644 --- a/src/templates/postpreview/index.tsx +++ b/src/templates/postpreview/index.tsx @@ -1,13 +1,15 @@ -import React from 'react' +import * as React from 'react' import { Link } from 'gatsby' -import { GatsbyImage } from 'gatsby-plugin-image' +import { GatsbyImage, IGatsbyImageData } from 'gatsby-plugin-image' import styled from 'styled-components' import getDescription from '../shared/getDescription' -export const StyledLink = styled((props) => )` +import type { PostNode } from '../../types' + +export const StyledLink = styled(Link)` text-decoration: none; color: black; &:hover { @@ -17,7 +19,8 @@ export const StyledLink = styled((props) => )` ` const StyledTitle = styled.h5` - font-family: 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, + font-family: + 'Montserrat', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 1rem; margin-bottom: 0; @@ -34,21 +37,31 @@ const StyledDesc = styled.p` margin-bottom: 100px; ` -const Post = ({ post }) => ( -
- - +interface PostPreviewProps { + post: PostNode +} - {post.frontmatter.title} - {post.frontmatter.date} - {getDescription(post.html)} - -
-) +const PostPreview: React.FC = ({ post }) => { + const previewImgData = post.frontmatter.previewImg?.childImageSharp + ?.gatsbyImageData as IGatsbyImageData | undefined + return ( +
+ + {previewImgData && ( + + )} -export default Post + {post.frontmatter.title} + {post.frontmatter.date} + {getDescription(post.html)} + +
+ ) +} + +export default PostPreview diff --git a/src/templates/shared/getDescription.ts b/src/templates/shared/getDescription.ts index 9ad7784..9391c22 100644 --- a/src/templates/shared/getDescription.ts +++ b/src/templates/shared/getDescription.ts @@ -7,7 +7,7 @@ const extractContent = (s: string): string => { return s } const getDescription = (content: string): string => { - return extractContent(content).substr(0, 100) + '...' + return extractContent(content).slice(0, 100) + '...' } export default getDescription diff --git a/src/templates/sidebar.tsx b/src/templates/sidebar.tsx index b1f01cf..e64d44e 100644 --- a/src/templates/sidebar.tsx +++ b/src/templates/sidebar.tsx @@ -1,12 +1,17 @@ -import React, { useState, useEffect } from 'react' +import * as React from 'react' import { Link, navigate } from 'gatsby' import kebabCase from 'lodash/kebabCase' import styled, { css } from 'styled-components' -import { pathPrefix } from '../../gatsby-config.js' +import { FaRss } from 'react-icons/fa' +import { pathPrefix, siteMetadata } from '../../gatsby-config' import { StyledHeading } from '../styledComponents/blog' import { SolidButton } from '../components/shared/styledComponents' +import type { PageContext, RecentPost, TagCount } from '../types' + +const rssFeedUrl = `${siteMetadata.siteUrl}rss.xml` + const styles = css` color: #314351; opacity: 0.8; @@ -29,10 +34,16 @@ const linkStyles = css` text-decoration: underline; } ` -const ArchiveLink = styled((props) => )` +const ArchiveLink = styled(Link)` ${linkStyles} ` -const RecentPostLink = styled((props) => )` +const RssAnchor = styled.a` + ${linkStyles} + display: flex; + align-items: center; + gap: 6px; +` +const RecentPostLink = styled(Link)` ${linkStyles} padding: 3px; border-bottom: 3px solid #e1e1e1; @@ -59,30 +70,44 @@ const StyledPara = styled.p` ${styles} ` -const Archives = ({ archives }) => ( +interface ArchivesProps { + archives: Record + basePath?: string +} + +const Archives: React.FC = ({ archives, basePath = '' }) => ( <> {Object.keys(archives) .sort() .reverse() - .map((year, index) => ( - + .map((year) => ( + {year} ({archives[year]}) ))} ) -const Categories = ({ tags }) => ( +interface CategoriesProps { + tags: TagCount[] + basePath?: string +} + +const Categories: React.FC = ({ tags, basePath = '' }) => ( <> {tags.map((tag, i) => ( - + {tag.name} ({tag.totalCount}) ))} ) -const RecentPosts = ({ posts }) => ( +interface RecentPostsProps { + posts: RecentPost[] +} + +const RecentPosts: React.FC = ({ posts }) => ( <> {posts.map((post) => ( @@ -92,22 +117,34 @@ const RecentPosts = ({ posts }) => ( ) -export const SideBar = ({ pageContext, location, notFoundPage = false }) => { +interface SideBarProps { + pageContext: PageContext + location: Location + notFoundPage?: boolean + basePath?: string +} + +export const SideBar: React.FC = ({ + pageContext, + location, + notFoundPage = false, + basePath = '' +}) => { const params = new URLSearchParams(location.search.substring(1)) const queryUrl = params?.get('s') || '' - const [query, setQuery] = useState(queryUrl) - useEffect(() => { + const [query, setQuery] = React.useState(queryUrl) + React.useEffect(() => { setQuery(queryUrl) }, [queryUrl]) - const handleSubmit = (event) => { + const handleSubmit = (event: React.FormEvent) => { event.preventDefault() navigate('/search?s=' + query) } - const _handleKeyDown = (event) => { + const _handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === 'Enter') { - handleSubmit(event) + navigate('/search?s=' + query) } } @@ -130,13 +167,16 @@ export const SideBar = ({ pageContext, location, notFoundPage = false }) => { type="text" value={query} onChange={(e) => setQuery(e.target.value)} - onKeyDown={(e) => _handleKeyDown(e)} + onKeyDown={_handleKeyDown} className="form-control" placeholder="Search" aria-label="Search" aria-describedby="button-addon2" /> - + navigate('/search?s=' + query)} + > Search
@@ -168,11 +208,17 @@ export const SideBar = ({ pageContext, location, notFoundPage = false }) => { <> Archives - + Categories - + + + + Subscribe + + RSS Feed + )} diff --git a/src/types/assets.d.ts b/src/types/assets.d.ts new file mode 100644 index 0000000..8b62da4 --- /dev/null +++ b/src/types/assets.d.ts @@ -0,0 +1,25 @@ +declare module '*.png' +declare module '*.jpg' +declare module '*.jpeg' +declare module '*.svg' +declare module '*.gif' +declare module '*.webp' +declare module '*.ico' +declare module '*.css' +declare module '*.scss' + +declare module 'react-use-flexsearch' { + export function useFlexSearch( + query: string | null, + index: string, + store: Record + ): Array> +} + +declare module '@browniebroke/gatsby-image-gallery' { + import * as React from 'react' + const Gallery: React.FC< + Record & { images: Array> } + > + export default Gallery +} diff --git a/src/types/declarations.d.ts b/src/types/declarations.d.ts new file mode 100644 index 0000000..ae088f7 --- /dev/null +++ b/src/types/declarations.d.ts @@ -0,0 +1,10 @@ +import 'react' + +declare module 'react' { + interface InputHTMLAttributes extends HTMLAttributes { + rules?: string + } + interface TextareaHTMLAttributes extends HTMLAttributes { + rules?: string + } +} diff --git a/src/types/index.ts b/src/types/index.ts index e69da0f..064ecff 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1 +1,2 @@ export * from './nostr' +export * from './site' diff --git a/src/types/site.ts b/src/types/site.ts new file mode 100644 index 0000000..a8fd41a --- /dev/null +++ b/src/types/site.ts @@ -0,0 +1,139 @@ +import { IGatsbyImageData } from 'gatsby-plugin-image' +import * as React from 'react' +import type { IconType } from 'react-icons' + +export type PageType = 'index' | 'year' | 'category' | 'search' + +export interface RecentPost { + slug: string + title: string +} + +export interface TagCount { + name: string + totalCount: number +} + +export interface PageContext { + page: PageType + archives: Record + recentPosts: RecentPost[] + tags: TagCount[] + filter?: unknown + limit?: number + skip?: number + numPages?: number + currentPage?: number + year?: string + tag?: string +} + +export interface PostFrontmatter { + title: string + date: string + author?: string + authorLink?: string + description?: string + tags?: string[] + heading?: string + desc?: string + previewImg?: { + childImageSharp?: { + gatsbyImageData: IGatsbyImageData + } + } +} + +export interface PostNode { + id?: string + html: string + fields: { + slug: string + } + frontmatter: PostFrontmatter +} + +export interface LayoutProps { + location: Location + heroSection?: boolean + heading?: string + desc?: string + children?: React.ReactNode +} + +export interface HeroSectionProps { + location: Location + heading?: string + desc?: string +} + +export interface NavibarProps { + location: Location +} + +export interface ContainerProps { + children?: React.ReactNode +} + +export interface SectionProps { + children?: React.ReactNode + color?: string + bgColor?: string + bottomArrow?: boolean +} + +export interface SeoProps { + description?: string + lang?: string + meta?: Array<{ name?: string; property?: string; content?: string }> + title?: string + previewImg?: string +} + +export interface SolidButtonProps { + children: React.ReactNode + theme?: 'light' | 'dark' + type?: 'button' | 'submit' | 'reset' + disabled?: boolean + onClick?: React.MouseEventHandler +} + +export interface OutlineButtonProps { + children: React.ReactNode +} + +export interface FaqProps { + question: string + answer: string +} + +export interface FeatureProps { + title: string + desc: string + Icon: IconType + className?: string +} + +export interface ReasonProps { + text: string + bgColor?: string +} + +export interface ArtProps { + src: string + info?: string +} + +export interface StyledAnchorProps { + href: string + children?: React.ReactNode +} + +export type SearchPost = { + id: string + html: string + slug: string + title: string + date: string + previewImg?: PostFrontmatter['previewImg'] +} diff --git a/static/fonts/Montserrat-300.woff2 b/static/fonts/Montserrat-300.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..a83d2845fd8477a105d8ab05ac98d699f72950b3 GIT binary patch literal 18708 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