diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 05e0307..330ca82 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -19,8 +19,8 @@ jobs:
- name: Source environment variables
run: |
- sudo cp /srv/portfolio/.env ./
- sed -i 's/^PORT=.*/PORT=3300/' .env
+ sudo cp /srv/unforeseen-travels/.env ./
+ sed -i 's/^PORT=.*/PORT=3400/' .env
source .env
- name: Install pnpm
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index fba88b4..7364109 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -27,21 +27,21 @@ jobs:
- name: Source environment variables
run: |
- sudo cp /srv/portfolio/.env ./
- sed -i 's/^PORT=.*/PORT=3300/' .env
+ sudo cp /srv/unforeseen-travels/.env ./
+ sed -i 's/^PORT=.*/PORT=3400/' .env
source .env
- name: Install pnpm
run: sudo npm install -g pnpm
- name: Stop the production server
- run: sudo systemctl stop portfolio || echo "Failed to stop the server, continuing..."
+ run: sudo systemctl stop unforeseen-travels || echo "Failed to stop the server, continuing..."
- name: Steal ownership of production server directory
- run: sudo chown -R gh-runner:gh-runner /srv/portfolio
+ run: sudo chown -R gh-runner:gh-runner /srv/unforeseen-travels
- name: Link existing node modules
- run: sudo ln -s /srv/portfolio/node_modules /home/gh-runner/actions-runner/_work/portfolio/portfolio/
+ run: sudo ln -s /srv/unforeseen-travels/node_modules /home/gh-runner/actions-runner/_work/unforeseen-travels/unforeseen-travels/
- name: Install dependencies
run: pnpm install
@@ -52,21 +52,21 @@ jobs:
- name: Publish Executable
if: success()
run: |
- sudo find /srv/portfolio/ -mindepth 1 \
- ! -path '/srv/portfolio/media*' \
- ! -path '/srv/portfolio/node_modules*' \
- ! -name '/srv/portfolio/.git*' \
+ sudo find /srv/unforeseen-travels/ -mindepth 1 \
+ ! -path '/srv/unforeseen-travels/media*' \
+ ! -path '/srv/unforeseen-travels/node_modules*' \
+ ! -name '/srv/unforeseen-travels/.git*' \
! -name '.env' \
! -name 'log' \
! -name 'tmp' -exec rm -rf {} +
sudo rsync -av --exclude 'node_modules' --exclude 'media' --exclude '.env' --exclude '.git' \
- --exclude 'log' --exclude 'tmp' /home/gh-runner/actions-runner/_work/portfolio/portfolio/ /srv/portfolio/
+ --exclude 'log' --exclude 'tmp' /home/gh-runner/actions-runner/_work/unforeseen-travels/unforeseen-travels/ /srv/unforeseen-travels/
- name: Install deps in prod after copy to be safe
if: success()
run: |
- cd /srv/portfolio
+ cd /srv/unforeseen-travels
pnpm install
- name: Handle failure
@@ -76,10 +76,10 @@ jobs:
- name: Restore permissions in production directory
if: always()
run: |
- sudo chown -R www-data:www-data /srv/portfolio/
- sudo chmod -R 755 /srv/portfolio/
+ sudo chown -R www-data:www-data /srv/unforeseen-travels/
+ sudo chmod -R 755 /srv/unforeseen-travels/
sudo chown -R gh-runner:gh-runner /home/gh-runner/
- name: Start production server
if: always()
- run: sudo systemctl start portfolio
+ run: sudo systemctl start unforeseen-travels
diff --git a/README.md b/README.md
index 2326233..0224c90 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,7 @@
-# Portfolio Site
+# Unforeseen Travels
-This is my personal portfolio site built with Payload CMS (version 2 via 'npx-create-payload-app@latest', updating to 3 beta soon). The site showcases my work and skills, featuring custom blocks for enhanced interactivity and visual appeal.
+More info coming soon...
## Key Features
-
-- **Custom Babylon.js 3D Model Viewer Block**: A fully customizable 3D model viewer built using Babylon.js, allowing dynamic interaction with 3D models directly on the portfolio pages.
- **IconRow Block**: A versatile block for displaying a row of icons, ideal for highlighting key technologies, tools, or skillsets in a visually appealing manner.
-
-## Technologies Used
-
-- **Payload CMS**: A headless CMS used to manage content efficiently, currently running on version 2 with plans to upgrade to version 3 beta.
-- **Babylon.js**: A powerful 3D engine for creating the interactive 3D model viewer.
-- **Custom Blocks**: Tailored blocks like the Babylon 3D Model Viewer and IconRow, designed to enhance the functionality and aesthetics of the site.
diff --git a/csp.js b/csp.js
index 49dcb5d..2a118e1 100644
--- a/csp.js
+++ b/csp.js
@@ -12,7 +12,7 @@ const policies = {
],
'font-src': ["'self'"],
'frame-src': ["'self'"],
- 'connect-src': ["'self'", 'https://maps.googleapis.com', 'http://localhost:33000'],
+ 'connect-src': ["'self'", 'https://maps.googleapis.com', 'http://localhost:34000'],
}
module.exports = Object.entries(policies)
diff --git a/next-env.d.ts b/next-env.d.ts
index 4f11a03..40c3d68 100644
--- a/next-env.d.ts
+++ b/next-env.d.ts
@@ -2,4 +2,4 @@
///
// NOTE: This file should not be edited
-// see https://nextjs.org/docs/basic-features/typescript for more information.
+// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
diff --git a/package.json b/package.json
index 5a55b05..2c57b4a 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "name": "portfolio",
+ "name": "unforeseentravels",
"description": "Website template for Payload",
"version": "1.0.0",
"main": "dist/server.js",
diff --git a/src/admin/css/admin.css b/src/admin/css/admin.css
index 3330f8e..6e3ae6b 100644
--- a/src/admin/css/admin.css
+++ b/src/admin/css/admin.css
@@ -5,3 +5,11 @@ body {
.nav {
background: rgba(0, 0, 0, 0.8);
}
+
+.nav nav a {
+ color: white;
+}
+
+.nav-group__toggle {
+ color: #c0c0c0
+}
diff --git a/src/app/(pages)/styleguide/content-block/page.tsx b/src/app/(pages)/styleguide/content-block/page.tsx
index 105dd80..1336ded 100644
--- a/src/app/(pages)/styleguide/content-block/page.tsx
+++ b/src/app/(pages)/styleguide/content-block/page.tsx
@@ -29,6 +29,18 @@ export default async function ContentBlockPage() {
text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
},
],
+ useImage: false,
+ inlineMedia: {
+ imageScale: 100,
+ borderRadius: 50,
+ media: {
+ url: '/path/to/icon1.jpg',
+ alt: 'Icon 1',
+ id: 0,
+ createdAt: new Date().toDateString(),
+ updatedAt: new Date().toDateString(),
+ },
+ },
},
]}
/>
diff --git a/src/app/_blocks/Content/index.module.scss b/src/app/_blocks/Content/index.module.scss
index 63a93d9..61d2efe 100644
--- a/src/app/_blocks/Content/index.module.scss
+++ b/src/app/_blocks/Content/index.module.scss
@@ -37,6 +37,12 @@
}
}
+.columnImageContainer {
+ overflow: hidden;
+ margin: 0 auto;
+ image-rendering: optimizeQuality;
+}
+
.link {
margin-top: var(--base);
}
diff --git a/src/app/_blocks/Content/index.tsx b/src/app/_blocks/Content/index.tsx
index da228b9..8ed8c85 100644
--- a/src/app/_blocks/Content/index.tsx
+++ b/src/app/_blocks/Content/index.tsx
@@ -3,6 +3,7 @@ import React from 'react'
import { Page } from '../../../payload/payload-types'
import { Gutter } from '../../_components/Gutter'
import { CMSLink } from '../../_components/Link'
+import { Media } from '../../_components/Media'
import RichText from '../../_components/RichText'
import classes from './index.module.scss'
@@ -22,11 +23,28 @@ export const ContentBlock: React.FC<
{columns &&
columns.length > 0 &&
columns.map((col, index) => {
- const { enableLink, richText, link, size } = col
+ const { enableLink, richText, link, size, useImage, inlineMedia } = col
+
+ if (useImage && !inlineMedia) return
Improper image config...
+
+ const { imageScale, borderRadius, media } = inlineMedia
return (
+ {useImage && (
+ <>
+
+
+
+ >
+ )}
{enableLink &&
}
)
diff --git a/src/app/_graphql/blocks.ts b/src/app/_graphql/blocks.ts
index 0d673a9..451d212 100644
--- a/src/app/_graphql/blocks.ts
+++ b/src/app/_graphql/blocks.ts
@@ -1,6 +1,6 @@
import { CATEGORIES } from './categories'
import { LINK_FIELDS } from './link'
-import { MEDIA } from './media'
+import { INLINE_MEDIA, MEDIA } from './media'
import { META } from './meta'
export const CALL_TO_ACTION = `
@@ -20,6 +20,8 @@ export const CONTENT = `
invertBackground
columns {
size
+ useImage
+ ${INLINE_MEDIA}
richText
enableLink
link ${LINK_FIELDS()}
diff --git a/src/app/_graphql/media.ts b/src/app/_graphql/media.ts
index fbf8e52..ed7225b 100644
--- a/src/app/_graphql/media.ts
+++ b/src/app/_graphql/media.ts
@@ -10,3 +10,9 @@ caption
export const MEDIA = `media {
${MEDIA_FIELDS}
}`
+
+export const INLINE_MEDIA = `inlineMedia {
+imageScale
+borderRadius
+${MEDIA}
+}`
diff --git a/src/payload/blocks/Content/index.ts b/src/payload/blocks/Content/index.ts
index 8568aa4..b229fe0 100644
--- a/src/payload/blocks/Content/index.ts
+++ b/src/payload/blocks/Content/index.ts
@@ -1,5 +1,6 @@
import type { Block, Field } from 'payload/types'
+import { inlineMedia } from '../../fields/inlineMedia'
import { invertBackground } from '../../fields/invertBackground'
import link from '../../fields/link'
import richText from '../../fields/richText'
@@ -28,7 +29,24 @@ const columnFields: Field[] = [
},
],
},
- richText(),
+ {
+ name: 'useImage',
+ type: 'checkbox',
+ defaultValue: false,
+ },
+ inlineMedia({
+ overrides: {
+ admin: {
+ condition: (_, siblingData) => siblingData?.useImage === true,
+ },
+ },
+ }),
+ richText({
+ admin: {
+ condition: (_, siblingData) => siblingData?.useImage === false,
+ },
+ required: false,
+ }),
{
name: 'enableLink',
type: 'checkbox',
diff --git a/src/payload/fields/inlineMedia.ts b/src/payload/fields/inlineMedia.ts
new file mode 100644
index 0000000..b610481
--- /dev/null
+++ b/src/payload/fields/inlineMedia.ts
@@ -0,0 +1,36 @@
+import type { Field } from 'payload/types'
+
+import deepMerge from '../utilities/deepMerge'
+
+type InlineMediaType = (options?: { overrides?: Record }) => Field
+
+export const inlineMedia: InlineMediaType = ({ overrides = {} } = {}) => {
+ const defaultField: Field = {
+ name: 'inlineMedia',
+ type: 'group',
+ admin: {
+ condition: (_, siblingData) => siblingData?.useImage === true,
+ },
+ fields: [
+ {
+ name: 'imageScale',
+ type: 'number',
+ required: false,
+ },
+ {
+ name: 'borderRadius',
+ type: 'number',
+ required: false,
+ },
+ {
+ name: 'media',
+ type: 'upload',
+ relationTo: 'media',
+ required: false,
+ },
+ ],
+ }
+
+ // Merge the default field with any overrides
+ return deepMerge(defaultField, overrides)
+}
diff --git a/src/payload/generated-schema.graphql b/src/payload/generated-schema.graphql
index 97f102c..72b1b14 100644
--- a/src/payload/generated-schema.graphql
+++ b/src/payload/generated-schema.graphql
@@ -387,6 +387,8 @@ type Content {
type Content_Columns {
size: Content_Columns_size
+ useImage: Boolean
+ inlineMedia: Content_Columns_InlineMedia
richText(depth: Int): JSON
enableLink: Boolean
link: Content_Columns_Link
@@ -400,6 +402,200 @@ enum Content_Columns_size {
full
}
+type Content_Columns_InlineMedia {
+ imageScale: Float
+ borderRadius: Float
+ media(where: Content_Columns_InlineMedia_Media_where): Media
+}
+
+input Content_Columns_InlineMedia_Media_where {
+ alt: Content_Columns_InlineMedia_Media_alt_operator
+ caption: Content_Columns_InlineMedia_Media_caption_operator
+ updatedAt: Content_Columns_InlineMedia_Media_updatedAt_operator
+ createdAt: Content_Columns_InlineMedia_Media_createdAt_operator
+ url: Content_Columns_InlineMedia_Media_url_operator
+ filename: Content_Columns_InlineMedia_Media_filename_operator
+ mimeType: Content_Columns_InlineMedia_Media_mimeType_operator
+ filesize: Content_Columns_InlineMedia_Media_filesize_operator
+ width: Content_Columns_InlineMedia_Media_width_operator
+ height: Content_Columns_InlineMedia_Media_height_operator
+ focalX: Content_Columns_InlineMedia_Media_focalX_operator
+ focalY: Content_Columns_InlineMedia_Media_focalY_operator
+ id: Content_Columns_InlineMedia_Media_id_operator
+ AND: [Content_Columns_InlineMedia_Media_where_and]
+ OR: [Content_Columns_InlineMedia_Media_where_or]
+}
+
+input Content_Columns_InlineMedia_Media_alt_operator {
+ equals: String
+ not_equals: String
+ like: String
+ contains: String
+ in: [String]
+ not_in: [String]
+ all: [String]
+}
+
+input Content_Columns_InlineMedia_Media_caption_operator {
+ equals: JSON
+ not_equals: JSON
+ like: JSON
+ contains: JSON
+ exists: Boolean
+}
+
+input Content_Columns_InlineMedia_Media_updatedAt_operator {
+ equals: DateTime
+ not_equals: DateTime
+ greater_than_equal: DateTime
+ greater_than: DateTime
+ less_than_equal: DateTime
+ less_than: DateTime
+ like: DateTime
+ exists: Boolean
+}
+
+input Content_Columns_InlineMedia_Media_createdAt_operator {
+ equals: DateTime
+ not_equals: DateTime
+ greater_than_equal: DateTime
+ greater_than: DateTime
+ less_than_equal: DateTime
+ less_than: DateTime
+ like: DateTime
+ exists: Boolean
+}
+
+input Content_Columns_InlineMedia_Media_url_operator {
+ equals: String
+ not_equals: String
+ like: String
+ contains: String
+ in: [String]
+ not_in: [String]
+ all: [String]
+ exists: Boolean
+}
+
+input Content_Columns_InlineMedia_Media_filename_operator {
+ equals: String
+ not_equals: String
+ like: String
+ contains: String
+ in: [String]
+ not_in: [String]
+ all: [String]
+ exists: Boolean
+}
+
+input Content_Columns_InlineMedia_Media_mimeType_operator {
+ equals: String
+ not_equals: String
+ like: String
+ contains: String
+ in: [String]
+ not_in: [String]
+ all: [String]
+ exists: Boolean
+}
+
+input Content_Columns_InlineMedia_Media_filesize_operator {
+ equals: Float
+ not_equals: Float
+ greater_than_equal: Float
+ greater_than: Float
+ less_than_equal: Float
+ less_than: Float
+ exists: Boolean
+}
+
+input Content_Columns_InlineMedia_Media_width_operator {
+ equals: Float
+ not_equals: Float
+ greater_than_equal: Float
+ greater_than: Float
+ less_than_equal: Float
+ less_than: Float
+ exists: Boolean
+}
+
+input Content_Columns_InlineMedia_Media_height_operator {
+ equals: Float
+ not_equals: Float
+ greater_than_equal: Float
+ greater_than: Float
+ less_than_equal: Float
+ less_than: Float
+ exists: Boolean
+}
+
+input Content_Columns_InlineMedia_Media_focalX_operator {
+ equals: Float
+ not_equals: Float
+ greater_than_equal: Float
+ greater_than: Float
+ less_than_equal: Float
+ less_than: Float
+ exists: Boolean
+}
+
+input Content_Columns_InlineMedia_Media_focalY_operator {
+ equals: Float
+ not_equals: Float
+ greater_than_equal: Float
+ greater_than: Float
+ less_than_equal: Float
+ less_than: Float
+ exists: Boolean
+}
+
+input Content_Columns_InlineMedia_Media_id_operator {
+ equals: String
+ not_equals: String
+ like: String
+ contains: String
+ in: [String]
+ not_in: [String]
+ all: [String]
+ exists: Boolean
+}
+
+input Content_Columns_InlineMedia_Media_where_and {
+ alt: Content_Columns_InlineMedia_Media_alt_operator
+ caption: Content_Columns_InlineMedia_Media_caption_operator
+ updatedAt: Content_Columns_InlineMedia_Media_updatedAt_operator
+ createdAt: Content_Columns_InlineMedia_Media_createdAt_operator
+ url: Content_Columns_InlineMedia_Media_url_operator
+ filename: Content_Columns_InlineMedia_Media_filename_operator
+ mimeType: Content_Columns_InlineMedia_Media_mimeType_operator
+ filesize: Content_Columns_InlineMedia_Media_filesize_operator
+ width: Content_Columns_InlineMedia_Media_width_operator
+ height: Content_Columns_InlineMedia_Media_height_operator
+ focalX: Content_Columns_InlineMedia_Media_focalX_operator
+ focalY: Content_Columns_InlineMedia_Media_focalY_operator
+ id: Content_Columns_InlineMedia_Media_id_operator
+ AND: [Content_Columns_InlineMedia_Media_where_and]
+ OR: [Content_Columns_InlineMedia_Media_where_or]
+}
+
+input Content_Columns_InlineMedia_Media_where_or {
+ alt: Content_Columns_InlineMedia_Media_alt_operator
+ caption: Content_Columns_InlineMedia_Media_caption_operator
+ updatedAt: Content_Columns_InlineMedia_Media_updatedAt_operator
+ createdAt: Content_Columns_InlineMedia_Media_createdAt_operator
+ url: Content_Columns_InlineMedia_Media_url_operator
+ filename: Content_Columns_InlineMedia_Media_filename_operator
+ mimeType: Content_Columns_InlineMedia_Media_mimeType_operator
+ filesize: Content_Columns_InlineMedia_Media_filesize_operator
+ width: Content_Columns_InlineMedia_Media_width_operator
+ height: Content_Columns_InlineMedia_Media_height_operator
+ focalX: Content_Columns_InlineMedia_Media_focalX_operator
+ focalY: Content_Columns_InlineMedia_Media_focalY_operator
+ id: Content_Columns_InlineMedia_Media_id_operator
+ AND: [Content_Columns_InlineMedia_Media_where_and]
+ OR: [Content_Columns_InlineMedia_Media_where_or]
+}
+
type Content_Columns_Link {
type: Content_Columns_Link_type
newTab: Boolean
diff --git a/src/payload/payload-types.ts b/src/payload/payload-types.ts
index afcd0f1..348cf5c 100644
--- a/src/payload/payload-types.ts
+++ b/src/payload/payload-types.ts
@@ -87,9 +87,17 @@ export interface Page {
columns?:
| {
size?: ('oneThird' | 'half' | 'twoThirds' | 'full') | null;
- richText: {
- [k: string]: unknown;
- }[];
+ useImage?: boolean | null;
+ inlineMedia?: {
+ imageScale?: number | null;
+ borderRadius?: number | null;
+ media?: number | Media | null;
+ };
+ richText?:
+ | {
+ [k: string]: unknown;
+ }[]
+ | null;
enableLink?: boolean | null;
link?: {
type?: ('reference' | 'custom') | null;
@@ -340,9 +348,17 @@ export interface Post {
columns?:
| {
size?: ('oneThird' | 'half' | 'twoThirds' | 'full') | null;
- richText: {
- [k: string]: unknown;
- }[];
+ useImage?: boolean | null;
+ inlineMedia?: {
+ imageScale?: number | null;
+ borderRadius?: number | null;
+ media?: number | Media | null;
+ };
+ richText?:
+ | {
+ [k: string]: unknown;
+ }[]
+ | null;
enableLink?: boolean | null;
link?: {
type?: ('reference' | 'custom') | null;
@@ -504,9 +520,17 @@ export interface Post {
columns?:
| {
size?: ('oneThird' | 'half' | 'twoThirds' | 'full') | null;
- richText: {
- [k: string]: unknown;
- }[];
+ useImage?: boolean | null;
+ inlineMedia?: {
+ imageScale?: number | null;
+ borderRadius?: number | null;
+ media?: number | Media | null;
+ };
+ richText?:
+ | {
+ [k: string]: unknown;
+ }[]
+ | null;
enableLink?: boolean | null;
link?: {
type?: ('reference' | 'custom') | null;
@@ -715,9 +739,17 @@ export interface Project {
columns?:
| {
size?: ('oneThird' | 'half' | 'twoThirds' | 'full') | null;
- richText: {
- [k: string]: unknown;
- }[];
+ useImage?: boolean | null;
+ inlineMedia?: {
+ imageScale?: number | null;
+ borderRadius?: number | null;
+ media?: number | Media | null;
+ };
+ richText?:
+ | {
+ [k: string]: unknown;
+ }[]
+ | null;
enableLink?: boolean | null;
link?: {
type?: ('reference' | 'custom') | null;
diff --git a/src/payload/payload.config.ts b/src/payload/payload.config.ts
index 584bd40..9183405 100644
--- a/src/payload/payload.config.ts
+++ b/src/payload/payload.config.ts
@@ -24,7 +24,7 @@ import { Header } from './globals/Header'
import { Settings } from './globals/Settings'
const generateTitle: GenerateTitle = () => {
- return 'My Website'
+ return 'Unforeseen Travels'
}
dotenv.config({