fix(web): remove redundant prop-types and unblock lint pipeline
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 10s
Build & Deploy / 🧪 QA (push) Failing after 2m24s
Build & Deploy / 🏗️ Build (push) Failing after 3m40s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 3s
1
.gitignore
vendored
@@ -3,6 +3,7 @@ dist/
|
||||
.next/
|
||||
out/
|
||||
.contentlayer/
|
||||
.pnpm-store
|
||||
|
||||
# generated types
|
||||
.astro/
|
||||
|
||||
@@ -5,14 +5,12 @@ WORKDIR /app
|
||||
# Arguments for build-time configuration
|
||||
ARG NEXT_PUBLIC_BASE_URL
|
||||
ARG NEXT_PUBLIC_TARGET
|
||||
ARG DIRECTUS_URL
|
||||
ARG UMAMI_API_ENDPOINT
|
||||
ARG NPM_TOKEN
|
||||
|
||||
# Environment variables for Next.js build
|
||||
ENV NEXT_PUBLIC_BASE_URL=$NEXT_PUBLIC_BASE_URL
|
||||
ENV NEXT_PUBLIC_TARGET=$NEXT_PUBLIC_TARGET
|
||||
ENV DIRECTUS_URL=$DIRECTUS_URL
|
||||
ENV UMAMI_API_ENDPOINT=$UMAMI_API_ENDPOINT
|
||||
ENV SKIP_RUNTIME_ENV_VALIDATION=true
|
||||
ENV CI=true
|
||||
|
||||
20
Dockerfile.dev
Normal file
@@ -0,0 +1,20 @@
|
||||
FROM node:20-alpine
|
||||
|
||||
# Install essential build tools if needed (e.g., for node-gyp)
|
||||
RUN apk add --no-cache libc6-compat python3 make g++
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Enable corepack for pnpm
|
||||
RUN corepack enable
|
||||
|
||||
# Pre-set the pnpm store directory to a location we can volume-mount
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
|
||||
# Set up pnpm store configuration
|
||||
RUN pnpm config set store-dir /pnpm/store
|
||||
|
||||
# Note: Dependency installation happens at runtime to support linked packages
|
||||
# and named volumes, but the base image is now optimized for the stack.
|
||||
EXPOSE 3000
|
||||
95
Posts.ts.tmp
Normal file
@@ -0,0 +1,95 @@
|
||||
import type { CollectionConfig } from "payload";
|
||||
import { lexicalEditor, BlocksFeature } from "@payloadcms/richtext-lexical";
|
||||
import { allBlocks } from "../blocks/allBlocks";
|
||||
|
||||
export const Posts: CollectionConfig = {
|
||||
slug: "posts",
|
||||
admin: {
|
||||
useAsTitle: "title",
|
||||
},
|
||||
access: {
|
||||
read: () => true, // Publicly readable API
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "aiOptimizer",
|
||||
type: "ui",
|
||||
admin: {
|
||||
position: "sidebar",
|
||||
components: {
|
||||
Field: "@/src/payload/components/OptimizeButton#OptimizeButton",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "title",
|
||||
type: "text",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "slug",
|
||||
type: "text",
|
||||
required: true,
|
||||
unique: true,
|
||||
admin: {
|
||||
position: "sidebar",
|
||||
},
|
||||
hooks: {
|
||||
beforeValidate: [
|
||||
({ value, data }) => {
|
||||
if (value) return value;
|
||||
if (data?.title) {
|
||||
return data.title
|
||||
.toLowerCase()
|
||||
.replace(/ /g, "-")
|
||||
.replace(/[^\w-]+/g, "");
|
||||
}
|
||||
return value;
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
type: "text",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "date",
|
||||
type: "date",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "tags",
|
||||
type: "array",
|
||||
required: true,
|
||||
fields: [
|
||||
{
|
||||
name: "tag",
|
||||
type: "text",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "featuredImage",
|
||||
type: "upload",
|
||||
relationTo: "media",
|
||||
admin: {
|
||||
description: "The main hero image for the blog post.",
|
||||
position: "sidebar",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "content",
|
||||
type: "richText",
|
||||
editor: lexicalEditor({
|
||||
features: ({ defaultFeatures }) => [
|
||||
...defaultFeatures,
|
||||
BlocksFeature({
|
||||
blocks: allBlocks,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
After Width: | Height: | Size: 953 KiB |
|
After Width: | Height: | Size: 198 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 5.0 MiB |
BIN
apps/public/media/build-first-digital-architecture-1024x572.png
Normal file
|
After Width: | Height: | Size: 915 KiB |
BIN
apps/public/media/build-first-digital-architecture-400x300.png
Normal file
|
After Width: | Height: | Size: 187 KiB |
BIN
apps/public/media/build-first-digital-architecture-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
apps/public/media/build-first-digital-architecture.png
Normal file
|
After Width: | Height: | Size: 5.2 MiB |
|
After Width: | Height: | Size: 654 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 987 KiB |
BIN
apps/public/media/builder-systems-threaten-independence.png
Normal file
|
After Width: | Height: | Size: 4.8 MiB |
BIN
apps/public/media/clean-code-for-business-value-1024x572.png
Normal file
|
After Width: | Height: | Size: 659 KiB |
BIN
apps/public/media/clean-code-for-business-value-400x300.png
Normal file
|
After Width: | Height: | Size: 137 KiB |
BIN
apps/public/media/clean-code-for-business-value-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
apps/public/media/clean-code-for-business-value.png
Normal file
|
After Width: | Height: | Size: 4.5 MiB |
BIN
apps/public/media/crm-synchronization-headless-1024x572.png
Normal file
|
After Width: | Height: | Size: 670 KiB |
BIN
apps/public/media/crm-synchronization-headless-400x300.png
Normal file
|
After Width: | Height: | Size: 133 KiB |
BIN
apps/public/media/crm-synchronization-headless-768x1024.png
Normal file
|
After Width: | Height: | Size: 987 KiB |
BIN
apps/public/media/crm-synchronization-headless.png
Normal file
|
After Width: | Height: | Size: 4.5 MiB |
|
After Width: | Height: | Size: 690 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
BIN
apps/public/media/digital-longevity-architecture-1024x572.png
Normal file
|
After Width: | Height: | Size: 743 KiB |
BIN
apps/public/media/digital-longevity-architecture-400x300.png
Normal file
|
After Width: | Height: | Size: 165 KiB |
BIN
apps/public/media/digital-longevity-architecture-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
apps/public/media/digital-longevity-architecture.png
Normal file
|
After Width: | Height: | Size: 4.9 MiB |
BIN
apps/public/media/fixed-price-digital-projects-1024x572.png
Normal file
|
After Width: | Height: | Size: 792 KiB |
BIN
apps/public/media/fixed-price-digital-projects-400x300.png
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
apps/public/media/fixed-price-digital-projects-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
apps/public/media/fixed-price-digital-projects.png
Normal file
|
After Width: | Height: | Size: 4.8 MiB |
BIN
apps/public/media/gdpr-conformity-system-approach-1024x572.png
Normal file
|
After Width: | Height: | Size: 891 KiB |
BIN
apps/public/media/gdpr-conformity-system-approach-400x300.png
Normal file
|
After Width: | Height: | Size: 198 KiB |
BIN
apps/public/media/gdpr-conformity-system-approach-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
apps/public/media/gdpr-conformity-system-approach.png
Normal file
|
After Width: | Height: | Size: 5.6 MiB |
BIN
apps/public/media/green-it-sustainable-web-1024x572.png
Normal file
|
After Width: | Height: | Size: 606 KiB |
BIN
apps/public/media/green-it-sustainable-web-400x300.png
Normal file
|
After Width: | Height: | Size: 133 KiB |
BIN
apps/public/media/green-it-sustainable-web-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
apps/public/media/green-it-sustainable-web.png
Normal file
|
After Width: | Height: | Size: 4.3 MiB |
BIN
apps/public/media/hidden-costs-of-wordpress-plugins-1024x572.png
Normal file
|
After Width: | Height: | Size: 606 KiB |
BIN
apps/public/media/hidden-costs-of-wordpress-plugins-400x300.png
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
apps/public/media/hidden-costs-of-wordpress-plugins-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
apps/public/media/hidden-costs-of-wordpress-plugins.png
Normal file
|
After Width: | Height: | Size: 4.5 MiB |
BIN
apps/public/media/mintel-thumb-1771868198228-1024x572.png
Normal file
|
After Width: | Height: | Size: 783 KiB |
BIN
apps/public/media/mintel-thumb-1771868198228-400x300.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
apps/public/media/mintel-thumb-1771868198228-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
apps/public/media/mintel-thumb-1771868198228.png
Normal file
|
After Width: | Height: | Size: 5.2 MiB |
BIN
apps/public/media/mintel-thumb-1771870270443-1024x572.png
Normal file
|
After Width: | Height: | Size: 635 KiB |
BIN
apps/public/media/mintel-thumb-1771870270443-400x300.png
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
apps/public/media/mintel-thumb-1771870270443-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
apps/public/media/mintel-thumb-1771870270443.png
Normal file
|
After Width: | Height: | Size: 4.8 MiB |
BIN
apps/public/media/no-us-cloud-platforms-1024x572.png
Normal file
|
After Width: | Height: | Size: 501 KiB |
BIN
apps/public/media/no-us-cloud-platforms-400x300.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
apps/public/media/no-us-cloud-platforms-768x1024.png
Normal file
|
After Width: | Height: | Size: 868 KiB |
BIN
apps/public/media/no-us-cloud-platforms.png
Normal file
|
After Width: | Height: | Size: 3.8 MiB |
BIN
apps/public/media/professional-hosting-operations-1024x572.png
Normal file
|
After Width: | Height: | Size: 633 KiB |
BIN
apps/public/media/professional-hosting-operations-400x300.png
Normal file
|
After Width: | Height: | Size: 141 KiB |
BIN
apps/public/media/professional-hosting-operations-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
apps/public/media/professional-hosting-operations.png
Normal file
|
After Width: | Height: | Size: 4.3 MiB |
BIN
apps/public/media/responsive-design-high-fidelity-1024x572.png
Normal file
|
After Width: | Height: | Size: 653 KiB |
BIN
apps/public/media/responsive-design-high-fidelity-400x300.png
Normal file
|
After Width: | Height: | Size: 134 KiB |
BIN
apps/public/media/responsive-design-high-fidelity-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
apps/public/media/responsive-design-high-fidelity.png
Normal file
|
After Width: | Height: | Size: 4.3 MiB |
BIN
apps/public/media/slow-loading-costs-customers-1024x572.png
Normal file
|
After Width: | Height: | Size: 752 KiB |
BIN
apps/public/media/slow-loading-costs-customers-400x300.png
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
apps/public/media/slow-loading-costs-customers-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
apps/public/media/slow-loading-costs-customers.png
Normal file
|
After Width: | Height: | Size: 5.0 MiB |
BIN
apps/public/media/website-without-cookie-banners-1024x572.png
Normal file
|
After Width: | Height: | Size: 620 KiB |
BIN
apps/public/media/website-without-cookie-banners-400x300.png
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
apps/public/media/website-without-cookie-banners-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
apps/public/media/website-without-cookie-banners.png
Normal file
|
After Width: | Height: | Size: 4.2 MiB |
BIN
apps/public/media/why-agencies-are-slow-1024x572.png
Normal file
|
After Width: | Height: | Size: 575 KiB |
BIN
apps/public/media/why-agencies-are-slow-400x300.png
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
apps/public/media/why-agencies-are-slow-768x1024.png
Normal file
|
After Width: | Height: | Size: 966 KiB |
BIN
apps/public/media/why-agencies-are-slow.png
Normal file
|
After Width: | Height: | Size: 4.3 MiB |
BIN
apps/public/media/why-no-templates-matter-1024x572.png
Normal file
|
After Width: | Height: | Size: 862 KiB |
BIN
apps/public/media/why-no-templates-matter-400x300.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
apps/public/media/why-no-templates-matter-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
apps/public/media/why-no-templates-matter.png
Normal file
|
After Width: | Height: | Size: 5.0 MiB |
BIN
apps/public/media/why-websites-break-after-updates-1024x572.png
Normal file
|
After Width: | Height: | Size: 620 KiB |
BIN
apps/public/media/why-websites-break-after-updates-400x300.png
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
apps/public/media/why-websites-break-after-updates-768x1024.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
apps/public/media/why-websites-break-after-updates.png
Normal file
|
After Width: | Height: | Size: 4.8 MiB |
@@ -1,4 +1,12 @@
|
||||
"use server";
|
||||
import { handleServerFunctions as payloadHandleServerFunctions } from "@payloadcms/next/layouts";
|
||||
import config from "@payload-config";
|
||||
import { importMap } from "./admin/importMap";
|
||||
|
||||
export const handleServerFunctions = payloadHandleServerFunctions;
|
||||
export const handleServerFunctions = async (args: any) => {
|
||||
return payloadHandleServerFunctions({
|
||||
...args,
|
||||
config,
|
||||
importMap,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,6 +1,99 @@
|
||||
import { OptimizeButton as OptimizeButton_a629b3460534b7aa208597fdc5e30aec } from "@/src/payload/components/OptimizeButton";
|
||||
import { GenerateSlugButton as GenerateSlugButton_63aadb132a046b3f001fac7a715e5717 } from "@/src/payload/components/FieldGenerators/GenerateSlugButton";
|
||||
import { default as default_76cec558bd86098fa1dab70b12eb818f } from "@/src/payload/components/TagSelector";
|
||||
import { GenerateThumbnailButton as GenerateThumbnailButton_39d416c162062cbe7173a99e3239786e } from "@/src/payload/components/FieldGenerators/GenerateThumbnailButton";
|
||||
import { RscEntryLexicalCell as RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e } from "@payloadcms/richtext-lexical/rsc";
|
||||
import { RscEntryLexicalField as RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e } from "@payloadcms/richtext-lexical/rsc";
|
||||
import { LexicalDiffComponent as LexicalDiffComponent_44fe37237e0ebf4470c9990d8cb7b07e } from "@payloadcms/richtext-lexical/rsc";
|
||||
import { BlocksFeatureClient as BlocksFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { AiFieldButton as AiFieldButton_da42292f87769a8025025b774910be6d } from "@/src/payload/components/FieldGenerators/AiFieldButton";
|
||||
import { InlineToolbarFeatureClient as InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { HorizontalRuleFeatureClient as HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { UploadFeatureClient as UploadFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { BlockquoteFeatureClient as BlockquoteFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { RelationshipFeatureClient as RelationshipFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { LinkFeatureClient as LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { ChecklistFeatureClient as ChecklistFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { OrderedListFeatureClient as OrderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { UnorderedListFeatureClient as UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { IndentFeatureClient as IndentFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { AlignFeatureClient as AlignFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { HeadingFeatureClient as HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { ParagraphFeatureClient as ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { InlineCodeFeatureClient as InlineCodeFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { SuperscriptFeatureClient as SuperscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { SubscriptFeatureClient as SubscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { StrikethroughFeatureClient as StrikethroughFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { UnderlineFeatureClient as UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { BoldFeatureClient as BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client";
|
||||
import { default as default_2ebf44fdf8ebc607cf0de30cff485248 } from "@/src/payload/components/ColorPicker";
|
||||
import { default as default_a1c6da8fb7dd9846a8b07123ff256d09 } from "@/src/payload/components/IconSelector";
|
||||
import { CollectionCards as CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1 } from "@payloadcms/next/rsc";
|
||||
|
||||
export const importMap = {
|
||||
"@/src/payload/components/OptimizeButton#OptimizeButton":
|
||||
OptimizeButton_a629b3460534b7aa208597fdc5e30aec,
|
||||
"@/src/payload/components/FieldGenerators/GenerateSlugButton#GenerateSlugButton":
|
||||
GenerateSlugButton_63aadb132a046b3f001fac7a715e5717,
|
||||
"@/src/payload/components/TagSelector#default":
|
||||
default_76cec558bd86098fa1dab70b12eb818f,
|
||||
"@/src/payload/components/FieldGenerators/GenerateThumbnailButton#GenerateThumbnailButton":
|
||||
GenerateThumbnailButton_39d416c162062cbe7173a99e3239786e,
|
||||
"@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell":
|
||||
RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e,
|
||||
"@payloadcms/richtext-lexical/rsc#RscEntryLexicalField":
|
||||
RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e,
|
||||
"@payloadcms/richtext-lexical/rsc#LexicalDiffComponent":
|
||||
LexicalDiffComponent_44fe37237e0ebf4470c9990d8cb7b07e,
|
||||
"@payloadcms/richtext-lexical/client#BlocksFeatureClient":
|
||||
BlocksFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@/src/payload/components/FieldGenerators/AiFieldButton#AiFieldButton":
|
||||
AiFieldButton_da42292f87769a8025025b774910be6d,
|
||||
"@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient":
|
||||
InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient":
|
||||
HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#UploadFeatureClient":
|
||||
UploadFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#BlockquoteFeatureClient":
|
||||
BlockquoteFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#RelationshipFeatureClient":
|
||||
RelationshipFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#LinkFeatureClient":
|
||||
LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#ChecklistFeatureClient":
|
||||
ChecklistFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#OrderedListFeatureClient":
|
||||
OrderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#UnorderedListFeatureClient":
|
||||
UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#IndentFeatureClient":
|
||||
IndentFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#AlignFeatureClient":
|
||||
AlignFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#HeadingFeatureClient":
|
||||
HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#ParagraphFeatureClient":
|
||||
ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#InlineCodeFeatureClient":
|
||||
InlineCodeFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#SuperscriptFeatureClient":
|
||||
SuperscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#SubscriptFeatureClient":
|
||||
SubscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#StrikethroughFeatureClient":
|
||||
StrikethroughFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#UnderlineFeatureClient":
|
||||
UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#BoldFeatureClient":
|
||||
BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#ItalicFeatureClient":
|
||||
ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@/src/payload/components/ColorPicker#default":
|
||||
default_2ebf44fdf8ebc607cf0de30cff485248,
|
||||
"@/src/payload/components/IconSelector#default":
|
||||
default_a1c6da8fb7dd9846a8b07123ff256d09,
|
||||
"@payloadcms/next/rsc#CollectionCards":
|
||||
CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1,
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@ import {
|
||||
CodeSnippet,
|
||||
AbstractCircuit,
|
||||
} from "@/src/components/Effects";
|
||||
import { getImgproxyUrl } from "@/src/utils/imgproxy";
|
||||
|
||||
import { Marker } from "@/src/components/Marker";
|
||||
|
||||
export default function AboutPage() {
|
||||
@@ -51,12 +51,7 @@ export default function AboutPage() {
|
||||
<div className="relative w-32 h-32 md:w-40 md:h-40 rounded-full overflow-hidden border border-slate-200 shadow-xl bg-white p-1 group">
|
||||
<div className="w-full h-full rounded-full overflow-hidden relative aspect-square">
|
||||
<img
|
||||
src={getImgproxyUrl("/marc-mintel.png", {
|
||||
width: 400,
|
||||
height: 400,
|
||||
resizing_type: "fill",
|
||||
gravity: "sm",
|
||||
})}
|
||||
src="/marc-mintel.png"
|
||||
alt="Marc Mintel"
|
||||
className="object-cover grayscale transition-all duration-1000 ease-in-out scale-110 group-hover:scale-100 group-hover:grayscale-0 w-full h-full"
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import * as React from "react";
|
||||
import type { Metadata } from "next";
|
||||
import { notFound } from "next/navigation";
|
||||
import { notFound, redirect } from "next/navigation";
|
||||
import { getPayloadHMR } from "@payloadcms/next/utilities";
|
||||
import configPromise from "@payload-config";
|
||||
import { getAllPosts } from "@/src/lib/posts";
|
||||
import { BlogPostHeader } from "@/src/components/blog/BlogPostHeader";
|
||||
import { Section } from "@/src/components/Section";
|
||||
@@ -9,6 +11,8 @@ import { BlogPostClient } from "@/src/components/BlogPostClient";
|
||||
import { TextSelectionShare } from "@/src/components/TextSelectionShare";
|
||||
import { BlogPostStickyBar } from "@/src/components/blog/BlogPostStickyBar";
|
||||
import { MDXContent } from "@/src/components/MDXContent";
|
||||
import { PayloadRichText } from "@/src/components/PayloadRichText";
|
||||
import { TableOfContents } from "@/src/components/TableOfContents";
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const allPosts = await getAllPosts();
|
||||
@@ -54,6 +58,18 @@ export default async function BlogPostPage({
|
||||
const post = allPosts.find((p) => p.slug === slug);
|
||||
|
||||
if (!post) {
|
||||
const payload = await getPayloadHMR({ config: configPromise });
|
||||
const redirectDoc = await payload.find({
|
||||
collection: "redirects",
|
||||
where: {
|
||||
from: { equals: slug },
|
||||
},
|
||||
});
|
||||
|
||||
if (redirectDoc.docs.length > 0) {
|
||||
redirect(`/blog/${redirectDoc.docs[0].to}`);
|
||||
}
|
||||
|
||||
notFound();
|
||||
}
|
||||
|
||||
@@ -102,7 +118,12 @@ export default async function BlogPostPage({
|
||||
)}
|
||||
|
||||
<div className="article-content max-w-none">
|
||||
<TableOfContents />
|
||||
{post.lexicalContent ? (
|
||||
<PayloadRichText data={post.lexicalContent} />
|
||||
) : (
|
||||
<MDXContent code={post.body.code} />
|
||||
)}
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
|
||||
12
apps/web/check-db.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export const run = async ({ payload }) => {
|
||||
const docs = await payload.find({
|
||||
collection: "context-files",
|
||||
limit: 100,
|
||||
});
|
||||
console.log(`--- DB CHECK ---`);
|
||||
console.log(`Found ${docs.totalDocs} context files.`);
|
||||
docs.docs.forEach((doc) => {
|
||||
console.log(`- ${doc.filename}`);
|
||||
});
|
||||
process.exit(0);
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
# Marc — digital problem solver
|
||||
|
||||
## Identity
|
||||
- Name: Marc Mintel
|
||||
- Mail: marc@mintel.me
|
||||
- Location: Vulkaneifel, Germany
|
||||
- Role: Independent digital problem solver
|
||||
- Mode: Solo
|
||||
- Focus: Understanding problems and building practical solutions
|
||||
|
||||
## What I do
|
||||
I work on digital problems and build tools, scripts, and systems to solve them.
|
||||
Sometimes that means code, sometimes automation, sometimes AI, sometimes something else.
|
||||
The tool is secondary. The problem comes first.
|
||||
|
||||
## How I work
|
||||
- I try things
|
||||
- I break things
|
||||
- I fix things
|
||||
- I write down what I learned
|
||||
|
||||
## What this blog is
|
||||
A public notebook of:
|
||||
- things I figured out
|
||||
- mistakes I made
|
||||
- tools I tested
|
||||
- small insights that might be useful later
|
||||
|
||||
Mostly short entries.
|
||||
Mostly practical.
|
||||
|
||||
## Why no portfolio
|
||||
Finished projects get outdated.
|
||||
Understanding doesn’t.
|
||||
|
||||
This blog shows how I approach problems, not how pretty something looked last year.
|
||||
|
||||
## Topics
|
||||
- Vibe coding with AI
|
||||
- Debugging and problem solving
|
||||
- Mac tools and workflows
|
||||
- Automation
|
||||
- Small scripts and systems
|
||||
- Learning notes
|
||||
- FOSS
|
||||
|
||||
## Audience
|
||||
People who:
|
||||
- build things
|
||||
- work with computers
|
||||
- solve problems
|
||||
- and don’t need marketing talk
|
||||
|
||||
## Tone
|
||||
- calm
|
||||
- factual
|
||||
- direct
|
||||
- no hype
|
||||
- no self-promotion
|
||||
|
||||
## Core idea
|
||||
Write things down.
|
||||
So I don’t forget.
|
||||
And so others might find them useful.
|
||||
@@ -1,43 +0,0 @@
|
||||
Prinzipien
|
||||
|
||||
Ich arbeite nach klaren Grundsätzen, die sicherstellen, dass meine Kunden fair, transparent und langfristig profitieren.
|
||||
|
||||
⸻
|
||||
|
||||
1. Volle Preis-Transparenz
|
||||
Alle Kosten sind offen und nachvollziehbar.
|
||||
Es gibt keine versteckten Gebühren, keine Abos, keine Lock-ins.
|
||||
Jeder Kunde sieht genau, wofür er bezahlt.
|
||||
|
||||
⸻
|
||||
|
||||
2. Quellcode & Projektzugang
|
||||
Auf Wunsch erhalten Kunden jederzeit den vollständigen Source Code und eine nachvollziehbare Struktur.
|
||||
Damit kann jeder andere Entwickler problemlos weiterarbeiten.
|
||||
Niemand kann später behaupten, der Code sei „Messy“ oder unbrauchbar.
|
||||
|
||||
⸻
|
||||
|
||||
3. Best Practices & saubere Technik
|
||||
Ich setze konsequent bewährte Standards und dokumentierte Abläufe ein.
|
||||
Das sorgt dafür, dass Systeme wartbar, verständlich und erweiterbar bleiben – langfristig.
|
||||
|
||||
⸻
|
||||
|
||||
4. Verantwortung & Fairness
|
||||
Ich übernehme die technische Verantwortung für die Website.
|
||||
Ich garantiere keine Umsätze, Rankings oder rechtliche Ergebnisse – nur saubere Umsetzung und stabile Systeme.
|
||||
Wenn etwas nicht sinnvoll ist, sage ich es ehrlich.
|
||||
|
||||
⸻
|
||||
|
||||
5. Langfristiger Wert
|
||||
Eine Website ist ein Investment.
|
||||
Ich baue sie so, dass Anpassungen, Erweiterungen und Übergaben an andere Entwickler problemlos möglich sind.
|
||||
Das schützt Ihre Investition und vermeidet teure Neuaufbauten.
|
||||
|
||||
⸻
|
||||
|
||||
6. Zusammenarbeit ohne Tricks
|
||||
Keine künstlichen Deadlines, kein unnötiger Overhead.
|
||||
Kommunikation ist klar, Entscheidungen nachvollziehbar, Übergaben sauber dokumentiert.
|
||||
54
apps/web/migrate-docs.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { getPayload } from "payload";
|
||||
import configPromise from "./payload.config";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
const payload = await getPayload({ config: configPromise });
|
||||
console.log("Payload initialized.");
|
||||
|
||||
const docsDir = path.resolve(process.cwd(), "docs");
|
||||
|
||||
if (!fs.existsSync(docsDir)) {
|
||||
console.log(`Docs directory not found at ${docsDir}`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(docsDir);
|
||||
let count = 0;
|
||||
|
||||
for (const file of files) {
|
||||
if (file.endsWith(".md")) {
|
||||
const content = fs.readFileSync(path.join(docsDir, file), "utf8");
|
||||
|
||||
// Check if already exists
|
||||
const existing = await payload.find({
|
||||
collection: "context-files",
|
||||
where: { filename: { equals: file } },
|
||||
});
|
||||
|
||||
if (existing.totalDocs === 0) {
|
||||
await payload.create({
|
||||
collection: "context-files",
|
||||
data: {
|
||||
filename: file,
|
||||
content: content,
|
||||
},
|
||||
});
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Migration successful! Added ${count} new context files to the database.`,
|
||||
);
|
||||
process.exit(0);
|
||||
} catch (e) {
|
||||
console.error("Migration failed:", e);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
34
apps/web/migrate-drafts.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { getPayload } from "payload";
|
||||
import configPromise from "./payload.config";
|
||||
|
||||
async function run() {
|
||||
const payload = await getPayload({ config: configPromise });
|
||||
const { docs } = await payload.find({
|
||||
collection: "posts",
|
||||
limit: 1000,
|
||||
});
|
||||
|
||||
console.log(`Found ${docs.length} posts. Checking status...`);
|
||||
|
||||
for (const doc of docs) {
|
||||
if (doc._status !== "published") {
|
||||
try {
|
||||
await payload.update({
|
||||
collection: "posts",
|
||||
id: doc.id,
|
||||
data: {
|
||||
_status: "published",
|
||||
},
|
||||
});
|
||||
console.log(`Updated "${doc.title}" to published.`);
|
||||
} catch (e) {
|
||||
console.error(`Failed to update ${doc.title}:`, e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Migration complete.");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
run();
|
||||
@@ -1,17 +1,15 @@
|
||||
import withMintelConfig from "@mintel/next-config";
|
||||
import { withPayload } from '@payloadcms/next/withPayload';
|
||||
|
||||
import createMDX from '@next/mdx';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const filename = fileURLToPath(import.meta.url);
|
||||
const dirname = path.dirname(filename);
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'],
|
||||
reactStrictMode: true,
|
||||
output: 'standalone',
|
||||
images: {
|
||||
loader: 'custom',
|
||||
loaderFile: './src/utils/imgproxy-loader.ts',
|
||||
},
|
||||
serverExternalPackages: ['@mintel/content-engine'],
|
||||
async rewrites() {
|
||||
return [
|
||||
// Umami proxy rewrite handled in app/stats/api/send/route.ts
|
||||
@@ -27,6 +25,13 @@ const nextConfig = {
|
||||
},
|
||||
];
|
||||
},
|
||||
webpack: (config) => {
|
||||
config.resolve.alias = {
|
||||
...config.resolve.alias,
|
||||
'@mintel/content-engine': path.resolve(dirname, 'node_modules/@mintel/content-engine'),
|
||||
};
|
||||
return config;
|
||||
},
|
||||
};
|
||||
|
||||
const withMDX = createMDX({
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
"version": "0.1.0",
|
||||
"description": "Technical problem solver's blog - practical insights and learning notes",
|
||||
"scripts": {
|
||||
"dev": "rm -rf .next && next dev",
|
||||
"dev": "pnpm run seed:context && next dev --turbo",
|
||||
"seed:context": "tsx ./seed-context.ts",
|
||||
"build": "next build --webpack",
|
||||
"start": "next start",
|
||||
"lint": "eslint app src scripts video",
|
||||
@@ -40,6 +41,7 @@
|
||||
"@payloadcms/email-nodemailer": "^3.77.0",
|
||||
"@payloadcms/next": "^3.77.0",
|
||||
"@payloadcms/richtext-lexical": "^3.77.0",
|
||||
"@payloadcms/ui": "^3.77.0",
|
||||
"@react-pdf/renderer": "^4.3.2",
|
||||
"@remotion/bundler": "^4.0.414",
|
||||
"@remotion/cli": "^4.0.414",
|
||||
|
||||
@@ -70,6 +70,9 @@ export interface Config {
|
||||
users: User;
|
||||
media: Media;
|
||||
posts: Post;
|
||||
inquiries: Inquiry;
|
||||
redirects: Redirect;
|
||||
"context-files": ContextFile;
|
||||
"payload-kv": PayloadKv;
|
||||
"payload-locked-documents": PayloadLockedDocument;
|
||||
"payload-preferences": PayloadPreference;
|
||||
@@ -80,6 +83,9 @@ export interface Config {
|
||||
users: UsersSelect<false> | UsersSelect<true>;
|
||||
media: MediaSelect<false> | MediaSelect<true>;
|
||||
posts: PostsSelect<false> | PostsSelect<true>;
|
||||
inquiries: InquiriesSelect<false> | InquiriesSelect<true>;
|
||||
redirects: RedirectsSelect<false> | RedirectsSelect<true>;
|
||||
"context-files": ContextFilesSelect<false> | ContextFilesSelect<true>;
|
||||
"payload-kv": PayloadKvSelect<false> | PayloadKvSelect<true>;
|
||||
"payload-locked-documents":
|
||||
| PayloadLockedDocumentsSelect<false>
|
||||
@@ -95,8 +101,12 @@ export interface Config {
|
||||
defaultIDType: number;
|
||||
};
|
||||
fallbackLocale: null;
|
||||
globals: {};
|
||||
globalsSelect: {};
|
||||
globals: {
|
||||
"ai-settings": AiSetting;
|
||||
};
|
||||
globalsSelect: {
|
||||
"ai-settings": AiSettingsSelect<false> | AiSettingsSelect<true>;
|
||||
};
|
||||
locale: null;
|
||||
user: User;
|
||||
jobs: {
|
||||
@@ -201,12 +211,99 @@ export interface Post {
|
||||
title: string;
|
||||
slug: string;
|
||||
description: string;
|
||||
/**
|
||||
* Set a future date and save as 'Published' to schedule this post. It will not appear on the frontend until this date is reached.
|
||||
*/
|
||||
date: string;
|
||||
tags: {
|
||||
/**
|
||||
* Kategorisiere diesen Post mit einem eindeutigen Tag
|
||||
*/
|
||||
tag?: string | null;
|
||||
id?: string | null;
|
||||
}[];
|
||||
thumbnail?: string | null;
|
||||
/**
|
||||
* The main hero image for the blog post.
|
||||
*/
|
||||
featuredImage?: (number | null) | Media;
|
||||
content?: {
|
||||
root: {
|
||||
type: string;
|
||||
children: {
|
||||
type: any;
|
||||
version: number;
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
direction: ("ltr" | "rtl") | null;
|
||||
format: "left" | "start" | "center" | "right" | "end" | "justify" | "";
|
||||
indent: number;
|
||||
version: number;
|
||||
};
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
_status?: ("draft" | "published") | null;
|
||||
}
|
||||
/**
|
||||
* Contact form leads and inquiries.
|
||||
*
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "inquiries".
|
||||
*/
|
||||
export interface Inquiry {
|
||||
id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
companyName?: string | null;
|
||||
projectType?: string | null;
|
||||
message?: string | null;
|
||||
isFreeText?: boolean | null;
|
||||
/**
|
||||
* The JSON data from the configurator.
|
||||
*/
|
||||
config?:
|
||||
| {
|
||||
[k: string]: unknown;
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "redirects".
|
||||
*/
|
||||
export interface Redirect {
|
||||
id: number;
|
||||
/**
|
||||
* The old URL slug that should be redirected (e.g. 'old-post-name')
|
||||
*/
|
||||
from: string;
|
||||
/**
|
||||
* The new URL slug to redirect to (e.g. 'new-awesome-post')
|
||||
*/
|
||||
to: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "context-files".
|
||||
*/
|
||||
export interface ContextFile {
|
||||
id: number;
|
||||
/**
|
||||
* Exact filename (e.g. 'strategy.md'). The system uses this to identify the document during prompt generation.
|
||||
*/
|
||||
filename: string;
|
||||
/**
|
||||
* The raw markdown/text content of the document.
|
||||
*/
|
||||
content: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
@@ -246,6 +343,18 @@ export interface PayloadLockedDocument {
|
||||
| ({
|
||||
relationTo: "posts";
|
||||
value: number | Post;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: "inquiries";
|
||||
value: number | Inquiry;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: "redirects";
|
||||
value: number | Redirect;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: "context-files";
|
||||
value: number | ContextFile;
|
||||
} | null);
|
||||
globalSlug?: string | null;
|
||||
user: {
|
||||
@@ -378,7 +487,43 @@ export interface PostsSelect<T extends boolean = true> {
|
||||
tag?: T;
|
||||
id?: T;
|
||||
};
|
||||
thumbnail?: T;
|
||||
featuredImage?: T;
|
||||
content?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
_status?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "inquiries_select".
|
||||
*/
|
||||
export interface InquiriesSelect<T extends boolean = true> {
|
||||
name?: T;
|
||||
email?: T;
|
||||
companyName?: T;
|
||||
projectType?: T;
|
||||
message?: T;
|
||||
isFreeText?: T;
|
||||
config?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "redirects_select".
|
||||
*/
|
||||
export interface RedirectsSelect<T extends boolean = true> {
|
||||
from?: T;
|
||||
to?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "context-files_select".
|
||||
*/
|
||||
export interface ContextFilesSelect<T extends boolean = true> {
|
||||
filename?: T;
|
||||
content?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
@@ -423,6 +568,39 @@ export interface PayloadMigrationsSelect<T extends boolean = true> {
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "ai-settings".
|
||||
*/
|
||||
export interface AiSetting {
|
||||
id: number;
|
||||
/**
|
||||
* List of trusted B2B/Tech sources (e.g. 'Vercel Blog', 'Fireship', 'Theo - t3.gg') the AI should prioritize when researching facts or videos. This overrides the hardcoded defaults.
|
||||
*/
|
||||
customSources?:
|
||||
| {
|
||||
sourceName: string;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
updatedAt?: string | null;
|
||||
createdAt?: string | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "ai-settings_select".
|
||||
*/
|
||||
export interface AiSettingsSelect<T extends boolean = true> {
|
||||
customSources?:
|
||||
| T
|
||||
| {
|
||||
sourceName?: T;
|
||||
id?: T;
|
||||
};
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
globalType?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "auth".
|
||||
|
||||