initialize sanity but studio on localhost not wokring

This commit is contained in:
2025-10-01 10:04:16 -04:00
parent f016b39e5c
commit 07f29c9bb6
53 changed files with 15704 additions and 41 deletions

29
studio/.gitignore vendored Normal file
View File

@@ -0,0 +1,29 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# Dependencies
/node_modules
/.pnp
.pnp.js
# Compiled Sanity Studio
/dist
# Temporary Sanity runtime, generated by the CLI on every dev server start
/.sanity
# Logs
/logs
*.log
# Coverage directory used by testing tools
/coverage
# Misc
.DS_Store
*.pem
# Typescript
*.tsbuildinfo
# Dotenv and similar local-only files
*.local

9
studio/README.md Normal file
View File

@@ -0,0 +1,9 @@
# Sanity Clean Content Studio
Congratulations, you have now installed the Sanity Content Studio, an open-source real-time content editing environment connected to the Sanity backend.
Now you can do the following things:
- [Read “getting started” in the docs](https://www.sanity.io/docs/introduction/getting-started?utm_source=readme)
- [Join the Sanity community](https://www.sanity.io/community/join?utm_source=readme)
- [Extend and build plugins](https://www.sanity.io/docs/content-studio/extending?utm_source=readme)

2608
studio/bun.lock Normal file

File diff suppressed because it is too large Load Diff

3
studio/eslint.config.mjs Normal file
View File

@@ -0,0 +1,3 @@
import studio from '@sanity/eslint-config-studio'
export default [...studio]

38
studio/package.json Normal file
View File

@@ -0,0 +1,38 @@
{
"name": "briannelsondev",
"private": true,
"version": "1.0.0",
"main": "package.json",
"license": "UNLICENSED",
"scripts": {
"dev": "sanity dev",
"start": "sanity start",
"build": "sanity build",
"deploy": "sanity deploy",
"deploy-graphql": "sanity graphql deploy"
},
"keywords": [
"sanity"
],
"dependencies": {
"@sanity/code-input": "^6.0.1",
"@sanity/vision": "^4.10.2",
"react": "^19.1",
"react-dom": "^19.1",
"sanity": "^4.10.2",
"styled-components": "^6.1.18"
},
"devDependencies": {
"@sanity/eslint-config-studio": "^5.0.2",
"@types/react": "^19.1",
"eslint": "^9.28",
"prettier": "^3.5",
"typescript": "^5.8"
},
"prettier": {
"semi": false,
"printWidth": 100,
"bracketSpacing": false,
"singleQuote": true
}
}

15
studio/sanity.cli.ts Normal file
View File

@@ -0,0 +1,15 @@
import {defineCliConfig} from 'sanity/cli'
export default defineCliConfig({
api: {
projectId: 'etj370e2',
dataset: 'production'
},
deployment: {
/**
* Enable auto-updates for studios.
* Learn more at https://www.sanity.io/docs/cli#auto-updates
*/
autoUpdates: true,
}
})

27
studio/sanity.config.ts Normal file
View File

@@ -0,0 +1,27 @@
import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'
import {visionTool} from '@sanity/vision'
import {schemaTypes} from './schemaTypes'
import { codeInput } from '@sanity/code-input';
const projectId = process.env.PUBLIC_SANITY_PROJECT_ID!;
const dataset = process.env.PUBLIC_SANITY_DATASET!;
export default defineConfig({
name: 'default',
title: 'briannelson.dev',
basePath: "/admin",
projectId,
dataset,
plugins: [
structureTool(),
visionTool(),
codeInput(),
],
schema: {
types: schemaTypes,
},
})

View File

@@ -0,0 +1,57 @@
import {ComposeIcon} from '@sanity/icons'
export default {
name: 'blogs',
title: 'Blogs',
type: 'document',
icon: ComposeIcon,
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96,
},
},
{
name: 'description',
title: 'Description',
type: 'text',
description: 'Enter a short snippit of the blog'
},
{
name: 'mainImage',
title: 'Main Image',
type: 'image',
options: [
{
hotspot: true
}
]
},
{
name: 'Categories',
title: 'categories',
type: 'array',
of: [{type: 'reference', to: {type: 'categories'}}]
},
{
name: 'publishedAt',
title: 'Published at',
type: 'datetime'
},
{
name: 'body',
title: 'Body',
type: 'blockContent'
}
],
}

View File

@@ -0,0 +1,20 @@
import { defineField, defineType } from 'sanity';
export const categories = defineType({
name: 'categories',
title: 'Categories',
type: 'document',
fields: [
defineField({
name: 'name',
title: 'Name',
type: 'string',
validation: Rule => Rule.required()
}),
defineField({
name: 'description',
title: 'Description',
type: 'text'
}),
],
})

View File

@@ -0,0 +1,60 @@
import { defineField, defineType } from "sanity";
export const frontend = defineType({
name: 'frontend',
title: 'Frontend Mentor',
type: 'document',
fieldsets: [
{
name: 'options',
options: {
collapsible: true,
collapsed: false
}
}
],
fields: [
defineField({
name: 'title',
title: 'Title',
type: 'string',
}),
defineField({
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96
},
}),
defineField({
name: 'qrCode',
title: 'QR Code Component',
type: 'qrCode',
fieldset: 'options'
}),
defineField({
name: 'resultsSummary',
title: 'Results Summary',
type: 'resultsSum',
fieldset: 'options'
}),
defineField({
name: 'productPrev',
title: 'Product Preview',
type: 'productInfo',
fieldset: 'options'
}),
defineField({
name: 'news',
type: 'newsData',
fieldset: 'options'
}),
defineField({
name: 'launch',
type: 'launchDate',
fieldset: 'options'
}),
],
})

View File

@@ -0,0 +1,68 @@
import { defineField, defineType } from "sanity";
export const homepage = defineType({
name: 'homepage',
title: 'Homepage',
type: 'document',
fieldsets: [
{
name: 'seo',
title: 'Metadata & SEO',
description: 'Use these fields to override the default metadata',
options: {
collapsible: true,
collapsed: true,
}
},
{
name: 'title',
title: 'Page Title'
}
],
fields: [
defineField({
name: 'title',
title: 'Title',
type: 'string',
fieldset: 'title'
}),
defineField({
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96
},
fieldset: 'title'
}),
defineField({
name: 'body',
title: 'Body',
type: 'blockContent'
}),
defineField({
name: 'cta',
title: 'Call to Action',
type: 'cta',
}),
defineField({
name: 'tech',
title: "Tech",
type: 'array',
of: [
{
type: 'reference',
to: [
{type: 'technologies'}
]
}
]
}),
defineField({
name: 'seo',
type: 'seo',
fieldset: 'seo'
})
],
})

View File

@@ -0,0 +1,34 @@
import { defineField, defineType, validateBasePaths } from 'sanity';
import { ImagesIcon } from '@sanity/icons'
export const mediaLibrary = defineType({
name: 'media',
title: 'Media Library',
type: 'document',
icon: ImagesIcon,
fields: [
defineField({
name: 'image',
title: 'Image',
type: 'image',
options: {
hotspot: true
}
}),
defineField({
name: 'alt',
title: 'Alternative Text',
type: 'string',
validation: (Rule) => Rule.required().max(250),
description: 'This is used for SEO and accessibility',
}),
],
preview: {
select: {
title: 'alt',
url: 'image.asset.url',
media: 'image', //adding this makes the image show up in standard preview components
},
},
})

View File

@@ -0,0 +1,12 @@
export default {
name: 'metadata',
title: 'Metadata',
type: 'document',
fields: [
{
name: 'customTitle',
title: 'Custom Title',
type: 'string',
},
],
}

View File

@@ -0,0 +1,21 @@
export default {
name: 'navigation',
title: 'Navigation',
type: 'document',
fields: [
{
name: 'navigation',
title: 'Navigation Menu',
type: 'array',
of: [
{
type: 'reference',
to: [
{type: 'pages'},
{type: 'homepage'}
]
}
]
},
],
}

View File

@@ -0,0 +1,43 @@
import MyPreviewComponent from '../../../src/lib/components/MyPreviewComponent';
import { defineField, defineType } from 'sanity';
export const newsPost = defineType({
name: 'newsPost',
title: 'News Posts',
type: 'document',
fields: [
defineField({
name: 'title',
title: 'Title',
type: 'string'
}),
defineField({
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96
}
}),
defineField({
name: 'image',
type: 'reference',
to: {
type: 'media',
components: {
preview: MyPreviewComponent
}
},
}),
defineField({
name: 'previewText',
title: 'Preview Text',
type: 'text'
}),
defineField({
name: 'category',
type: 'string'
})
],
})

View File

@@ -0,0 +1,50 @@
import { defineField, defineType } from "sanity";
export const pages = defineType({
name: 'pages',
title: 'Pages',
type: 'document',
fieldsets: [
{
name: 'seo',
title: 'Metadata & SEO',
description: 'Use these fields to override the default metadata',
options: {
collapsible: true,
collapsed: true,
}
},
{
name: 'title',
title: 'Page Title'
}
],
fields: [
defineField({
name: 'title',
title: 'Title',
type: 'string',
fieldset: 'title'
}),
defineField({
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96
},
fieldset: 'title'
}),
defineField({
name: 'body',
title: 'Body',
type: 'blockContent'
}),
defineField({
name: 'seo',
type: 'seo',
fieldset: 'seo'
})
],
})

View File

@@ -0,0 +1,128 @@
import { defineField, defineType } from "sanity";
import {Stack, Card, Flex } from '@sanity/ui'
import { RocketIcon } from '@sanity/icons'
function MyPreviewComponent(props: any) {
const {title, url} = props
return (
<Flex align="center" justify="center" height="fill">
<Card border padding={3}>
<Stack space={3} marginBottom={3}>
<img src={url} alt={title} style={{width: '100%'}} />
</Stack>
</Card>
</Flex>
)
}
export const projects = defineType({
name: 'projects',
title: 'Projects',
type: 'document',
icon: RocketIcon,
fieldsets: [
{
name: 'title',
title: 'Title'
},
{
name: 'projectLinks',
title: 'Project Links'
}
],
fields: [
defineField({
name: 'title',
title: 'Project Title',
type: 'string',
fieldset: 'title'
}),
defineField({
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96
},
fieldset: 'title'
}),
defineField({
name: 'order',
title: 'Order',
type: 'number',
fieldset: 'title',
}),
defineField({
name: 'description',
title: 'Description',
type: 'text',
rows: 5
}),
defineField({
name: 'featured',
title: 'Featured',
type: 'boolean',
initialValue: false,
fieldset: 'title'
}),
defineField({
name: 'body',
title: 'Body',
type: 'blockContent',
}),
defineField({
name: 'image',
title: 'Main Image',
type: 'reference',
to: {
type: 'media',
components: {
preview: MyPreviewComponent
}
},
}),
defineField({
name: 'link',
title: 'Link to Project',
type: 'url',
fieldset: 'projectLinks'
}),
defineField({
name: 'github',
title: 'GitHub Reop',
type: 'url',
fieldset: 'projectLinks'
}),
defineField({
name: 'tags',
title: 'Tags',
type: 'array',
of: [
{
type: 'reference',
to: [
{type: 'categories'}
]
}
]
}),
defineField({
name: 'stats',
title: 'Statistics',
type: 'array',
of: [
{
type: 'stats',
}
]
}),
],
preview: {
select: {
title: 'title',
media: 'image'
}
}
})

View File

@@ -0,0 +1,27 @@
export default {
name: 'siteSettings',
title: 'Site Settings',
type: 'document',
fields: [
{
name: 'siteTitle',
title: 'Site Title',
type: 'string',
},
{
name: 'contact',
type: 'contact'
},
{
name: 'logo',
title: 'Logo',
type: 'image'
},
{
name: 'favicon',
title: 'Favicon',
type: 'image',
description: 'This is used for the tab favicon as well as the mobile menu'
},
],
}

View File

@@ -0,0 +1,26 @@
import { defineField, defineType } from "sanity";
import MyPreviewComponent from "../../../src/lib/components/MyPreviewComponent";
export const technologies = defineType({
name: 'technologies',
title: 'Technologies',
type: 'document',
fields: [
defineField({
name: 'title',
title: 'Title',
type: 'string',
}),
defineField({
name: 'image',
type: 'reference',
to: {
type: 'media',
components: {
preview: MyPreviewComponent
}
},
}),
],
})

View File

@@ -0,0 +1,49 @@
import blogs from "./documents/blogs";
import { categories } from "./documents/categories";
import { frontend } from "./documents/frontend";
import { homepage } from "./documents/homepage";
import { mediaLibrary } from "./documents/mediaLibrary";
import metadata from "./documents/metadata";
import navigation from "./documents/navigation";
import { newsPost } from "./documents/newsPosts";
import { pages } from "./documents/pages";
import { projects } from "./documents/projects";
import siteSettings from "./documents/siteSettings";
import { technologies } from "./documents/technologies";
import blockContent from "./objects/blockContent";
import contact from "./objects/contact";
import { cta } from "./objects/cta";
import { launchDate } from "./objects/feobj/launchDate";
import { newsData } from "./objects/feobj/newsData";
import { productInfo } from "./objects/feobj/productInfo";
import { qrCode } from "./objects/feobj/qrCode";
import { resultsSum } from "./objects/feobj/resultsSumm";
import { scores } from "./objects/feobj/scores";
import { seo } from "./objects/seo";
import { stats } from "./objects/stats";
export const schemaTypes = [
pages,
siteSettings,
homepage,
frontend,
contact,
metadata,
navigation,
blogs,
blockContent,
seo,
mediaLibrary,
projects,
categories,
stats,
cta,
qrCode,
resultsSum,
scores,
productInfo,
newsData,
newsPost,
technologies,
launchDate,
]

View File

@@ -0,0 +1,51 @@
export default {
name: 'blockContent',
title: 'Body',
type: 'array',
of: [
{
title: 'Block',
type: 'block',
styles: [
{title: 'Normal', value: 'normal'},
{title: 'H1', value: 'h1'},
{title: 'H2', value: 'h2'},
{title: 'H3', value: 'h3'},
{title: 'H4', value: 'h4'},
{title: 'Quote', value: 'blockquote'},
],
lists: [{title: 'Bullet', value: 'bullet'}],
// Marks let you mark up inline text in the block editor.
marks: {
// Decorators usually describe a single property e.g. a typographic
// preference or highlighting by editors.
decorators: [
{title: 'Strong', value: 'strong'},
{title: 'Emphasis', value: 'em'},
],
// Annotations can be any object structure e.g. a link or a footnote.
annotations: [
{
title: 'URL',
name: 'link',
type: 'object',
fields: [
{
title: 'URL',
name: 'href',
type: 'url',
},
],
},
],
},
},
{
title: 'Image',
type: 'image'
},
{
type: 'code'
}
],
}

View File

@@ -0,0 +1,43 @@
export default {
name: 'contact',
title: 'Contact Info',
type: 'object',
fields: [
{
name: 'email',
title: 'Main Email',
type: 'string',
validation: (Rule: any) =>
Rule.regex(
/[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/,
{
name: 'Email',
invert: false
}
)
},
{
name: 'phone',
title: 'Main Phone Number',
type: 'string',
validation: (Rule: any) =>
Rule.regex(
/^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/,
{
name: 'Phone',
invert: false
}
)
},
{
name: 'socials',
title: 'Socials',
type: 'array',
of: [
{name: 'facebook', title: 'Facebook', type: 'url'},
{name: 'twitter', title: 'Twitter', type: 'url'},
{name: 'instagram', title: 'Instagram', type: 'url'},
]
}
],
}

View File

@@ -0,0 +1,25 @@
import { defineField, defineType } from 'sanity';
export const cta = defineType({
name: 'cta',
title: 'Call to Action',
type: 'object',
fields: [
defineField({
name: 'title',
title: 'Title',
type: 'string',
validation: Rule => Rule.max(30).error('Keep this short')
}),
defineField({
name: 'link',
title: 'Link',
type: 'reference',
to: [
{type: 'pages'},
{type: 'projects'}
],
description: 'Keep your CTA to an internal page for SEO best practices'
})
],
})

View File

@@ -0,0 +1,17 @@
import { defineField, defineType } from 'sanity';
export const launchDate = defineType({
name: 'launchDate',
title: 'Launch Date',
type: 'object',
fields: [
defineField({
name: 'launchAt',
title: 'Launch At',
type: 'datetime'
})
],
options: {
collapsed: true
}
})

View File

@@ -0,0 +1,33 @@
import { defineField, defineType } from 'sanity';
export const newsData = defineType({
name: 'newsData',
title: 'News',
type: 'object',
fields: [
defineField({
name: 'nav',
title: 'Navigation',
type: 'array',
of: [
{type: 'string'}
]
}),
defineField({
name: 'posts',
title: 'Posts',
type: 'array',
of: [
{
type: 'reference',
to: [
{type: 'newsPost'}
]
}
]
})
],
options: {
collapsed: true
}
})

View File

@@ -0,0 +1,67 @@
import { defineField, defineType } from 'sanity';
import MyPreviewComponent from '../../../../src/lib/components/MyPreviewComponent';
export const productInfo = defineType({
name: 'productInfo',
title: 'Product Info',
type: 'object',
fields: [
defineField({
name: 'title',
title: 'Title',
type: 'string'
}),
defineField({
name: 'mobileImage',
type: 'reference',
to: {
type: 'media',
components: {
preview: MyPreviewComponent
}
},
}),
defineField({
name: 'deskImage',
type: 'reference',
to: {
type: 'media',
components: {
preview: MyPreviewComponent
}
},
}),
defineField({
name: 'price',
title: 'Price',
type: 'object',
fields: [
defineField({
name: 'ogPrice',
title: 'Original Price',
type: 'number'
}),
defineField({
name: 'newPrice',
title: 'New Price',
type: 'number'
}),
]
}),
defineField({
name: 'category',
title: 'Category',
type: 'string'
// I would make this a reference if there was more products
}),
defineField({
name: 'desc',
title: 'Description',
type: 'text'
})
],
options: {
collapsed: true
}
})

View File

@@ -0,0 +1,38 @@
import { defineField, defineType } from 'sanity';
import MyPreviewComponent from '../../../../src/lib/components/MyPreviewComponent';
export const qrCode = defineType({
name: 'qrCode',
title: 'QR Code',
type: 'object',
fields: [
defineField({
name: 'image',
type: 'reference',
to: {
type: 'media',
components: {
preview: MyPreviewComponent
}
},
}),
defineField({
name: 'text',
type: 'object',
fields: [
defineField({
name: 'title',
type: 'string',
}),
defineField({
name: 'subtitle',
type: 'string',
}),
]
})
],
options: {
collapsed: true
}
})

View File

@@ -0,0 +1,52 @@
import { defineField, defineType } from 'sanity';
export const resultsSum = defineType({
name: 'resultsSum',
title: 'Results Summary',
type: 'object',
fields: [
defineField({
name: 'allResults',
title: 'Results',
type: 'object',
fields: [
defineField({
name: 'resultArr',
type: 'array',
of: [
{
type: 'scores'
}
]
})
]
}),
defineField({
name: 'reaction',
title: 'Reaction',
type: 'number',
validation: Rule => Rule.max(100)
}),
defineField({
name: 'memory',
title: 'Memory',
type: 'number',
validation: Rule => Rule.max(100)
}),
defineField({
name: 'verbal',
title: 'Verbal',
type: 'number',
validation: Rule => Rule.max(100)
}),
defineField({
name: 'visual',
title: 'Visual',
type: 'number',
validation: Rule => Rule.max(100)
}),
],
options: {
collapsed: true
}
})

View File

@@ -0,0 +1,29 @@
import { defineField, defineType } from 'sanity';
export const scores = defineType({
name: 'scores',
title: 'Scores',
type: 'object',
fields: [
defineField({
name: 'title',
title: 'Title',
type: 'string'
}),
defineField({
name: 'score',
title: 'Score',
type: 'number',
validation: Rule => Rule.max(100)
})
],
options: {
columns: 2
},
preview: {
select: {
title: 'score',
subtitle: 'title'
}
}
})

View File

@@ -0,0 +1,30 @@
import { defineField, defineType } from "sanity";
export const seo = defineType({
name: 'seo',
title: 'SEO',
type: 'object',
fields: [
defineField({
name: 'title',
title: 'Meta Title',
type: 'string'
}),
defineField({
name: 'description',
title: 'Meta Description',
type: 'text'
}),
defineField({
name: 'keywords',
title: 'Keywords',
type: 'array',
of: [{type: 'string'}]
}),
defineField({
name: 'image',
title: 'Preview Image',
type: 'image'
})
]
})

View File

@@ -0,0 +1,28 @@
import { defineField, defineType } from 'sanity';
export const stats = defineType({
name: 'stats',
title: 'Statistics',
type: 'object',
fields: [
defineField({
name: 'number',
title: 'Number',
type: 'number'
}),
defineField({
name: 'title',
title: 'Title',
type: 'string'
}),
],
options: {
columns: 2
},
preview: {
select: {
title: 'number',
subtitle: 'title'
}
}
})

1
studio/static/.gitkeep Normal file
View File

@@ -0,0 +1 @@
Files placed here will be served by the Sanity server under the `/static`-prefix

17
studio/tsconfig.json Normal file
View File

@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "Preserve",
"moduleDetection": "force",
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
},
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}