diff --git a/.eslintrc.js b/.eslintrc.js index 2e9f3fc..cd70472 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,29 +2,24 @@ module.exports = { globals: { __PATH_PREFIX__: true, }, - 'parser': 'babel-eslint', // uses babel-eslint transforms - 'settings': { - 'react': { - 'version': 'detect', // detect react version + parser: "babel-eslint", // uses babel-eslint transforms + settings: { + react: { + version: "detect", // detect react version }, }, - 'env': { - 'node': true, // defines things like process.env when generating through node - 'browser': true + env: { + node: true, // defines things like process.env when generating through node + browser: true, }, - 'extends': [ - 'eslint:recommended', // use recommended configs - 'plugin:react/recommended', - 'plugin:react-hooks/recommended', + extends: [ + "eslint:recommended", // use recommended configs + "plugin:react/recommended", + "plugin:react-hooks/recommended", ], - 'rules': { - 'react/prop-types': 0, - 'quotes': ['warn', 'single'], - 'semi': 1, - 'indent': ['warn', 2], - 'comma-dangle': ['warn', 'always-multiline'], - 'no-unused-vars': 1, - 'jsx-quotes': 1, - 'react/jsx-sort-props': 1, + rules: { + "react/prop-types": 0, + "no-unused-vars": 1, + "react/jsx-sort-props": 1, }, }; diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f27c930..5ddaf2e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,9 +6,9 @@ name: deploy # events but only for the master branch on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: @@ -18,24 +18,24 @@ jobs: runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 - - name: Set Node.js - uses: actions/setup-node@master - with: - node-version: 16.x - - name: Install dependencies - run: yarn install --prod --pure-lockfile - - name: Lint - run: yarn run lint - - name: Build - run: yarn run build - - name: upload - uses: burnett01/rsync-deployments@4.1 - with: - switches: -zr --delete --exclude node_modules --exclude '.git*' - path: ./public/ - remote_path: www/personal-website - remote_host: droplet.chuckdries.com - remote_user: ${{ secrets.CI_USER }} - remote_key: ${{ secrets.CI_SSH_KEY }} + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + - name: Set Node.js + uses: actions/setup-node@master + with: + node-version: 16.x + - name: Install dependencies + run: yarn install --prod --pure-lockfile + - name: Lint + run: yarn run lint + - name: Build + run: yarn run build + - name: upload + uses: burnett01/rsync-deployments@4.1 + with: + switches: -zr --delete --exclude node_modules --exclude '.git*' + path: ./public/ + remote_path: www/personal-website + remote_host: droplet.chuckdries.com + remote_user: ${{ secrets.CI_USER }} + remote_key: ${{ secrets.CI_SSH_KEY }} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..18055b9 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,5 @@ +.cache +node_modules +old\ website +public +gatsby \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/.vscode/launch.json b/.vscode/launch.json index 3020d97..837b529 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,71 +1,68 @@ -{ - "version": "0.2.0", - "configurations": [{ - "name": "Launch Chrome", - "type": "chrome", - "request": "launch", - "url": "http://localhost:3000", - "sourceMaps": true, - "webRoot": "${workspaceRoot}" - }, - { - "name": "Launch Unix", - "type": "node", - "request": "launch", - "program": "/usr/local/bin/lite-server", - "stopOnEntry": false, - "args": [], - "cwd": "${workspaceRoot}", - "preLaunchTask": null, - "runtimeExecutable": null, - "runtimeArgs": [ - "--nolazy" - ], - "env": { - "NODE_ENV": "development" - }, - "externalConsole": false, - "sourceMaps": false, - "outDir": null - }, - { - "name": "Launch on Windows", - "type": "node", - "request": "launch", - "program": "C:\\Users\\chuckdries\\AppData\\Roaming\\npm\\node_modules\\lite-server\\index.js", - "stopOnEntry": false, - "args": [], - "cwd": "${workspaceRoot}", - "preLaunchTask": null, - "runtimeExecutable": null, - "runtimeArgs": [ - "--nolazy" - ], - "env": { - "NODE_ENV": "development" - }, - "console": "internalConsole", - "sourceMaps": true, - "outDir": null - }, - - { - "name": "Attach Chrome", - "type": "chrome", - "request": "attach", - "port": 9222 - }, - { - "name": "Attach", - "type": "node", - "request": "attach", - "port": 3000, - "address": "localhost", - "restart": false, - "sourceMaps": false, - "outDir": null, - "localRoot": "${workspaceRoot}", - "remoteRoot": null - } - ] -} \ No newline at end of file +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Chrome", + "type": "chrome", + "request": "launch", + "url": "http://localhost:3000", + "sourceMaps": true, + "webRoot": "${workspaceRoot}" + }, + { + "name": "Launch Unix", + "type": "node", + "request": "launch", + "program": "/usr/local/bin/lite-server", + "stopOnEntry": false, + "args": [], + "cwd": "${workspaceRoot}", + "preLaunchTask": null, + "runtimeExecutable": null, + "runtimeArgs": ["--nolazy"], + "env": { + "NODE_ENV": "development" + }, + "externalConsole": false, + "sourceMaps": false, + "outDir": null + }, + { + "name": "Launch on Windows", + "type": "node", + "request": "launch", + "program": "C:\\Users\\chuckdries\\AppData\\Roaming\\npm\\node_modules\\lite-server\\index.js", + "stopOnEntry": false, + "args": [], + "cwd": "${workspaceRoot}", + "preLaunchTask": null, + "runtimeExecutable": null, + "runtimeArgs": ["--nolazy"], + "env": { + "NODE_ENV": "development" + }, + "console": "internalConsole", + "sourceMaps": true, + "outDir": null + }, + + { + "name": "Attach Chrome", + "type": "chrome", + "request": "attach", + "port": 9222 + }, + { + "name": "Attach", + "type": "node", + "request": "attach", + "port": 3000, + "address": "localhost", + "restart": false, + "sourceMaps": false, + "outDir": null, + "localRoot": "${workspaceRoot}", + "remoteRoot": null + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index fe71598..1cf3971 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "python.linting.pylintEnabled": false -} \ No newline at end of file + "python.linting.pylintEnabled": false +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5cfa26c..7e7f519 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,16 +1,16 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "command": "gulp", - "tasks": [ - { - "label": "default", - "type": "gulp", - "task": "default", - "isBackground": true, - "problemMatcher": [], - "group": "build" - } - ] -} \ No newline at end of file +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "command": "gulp", + "tasks": [ + { + "label": "default", + "type": "gulp", + "task": "default", + "isBackground": true, + "problemMatcher": [], + "group": "build" + } + ] +} diff --git a/TODO.md b/TODO.md index 0938d47..82277b0 100644 --- a/TODO.md +++ b/TODO.md @@ -1,10 +1,12 @@ - Gallery + - [x] Custom image metadata - [ ] add metadata to image files - [ ] image details page (modal route?) - [ ] gallery page - Homepage + - [ ] homepage basic layout - [ ] homepage aesthetics - [ ] homepage to gallery page transition @@ -14,6 +16,7 @@ - [ ] About page? - Portfolio/Projects page + - basic layout - source data - aesthetics @@ -21,4 +24,4 @@ - [x] tailwind (done-ish) - [ ] typescript - [ ] graphql codegen -- [ ] static files (resume) \ No newline at end of file +- [ ] static files (resume) diff --git a/gatsby-browser.js b/gatsby-browser.js index 4fee747..1496df7 100644 --- a/gatsby-browser.js +++ b/gatsby-browser.js @@ -1,17 +1,17 @@ -import './src/styles/global.css'; -import posthog from 'posthog-js'; +import "./src/styles/global.css"; +import posthog from "posthog-js"; -const env = process.env.GATSBY_ACTIVE_ENV || process.env.NODE_ENV || 'development'; -if (env === 'production') { - posthog.init('HR8Gte105aCHNx2BqhL1XkbvH9kzKGptxjkbhuTj6Ek', { api_host: 'https://posthog.chuckdries.com' }); +const env = + process.env.GATSBY_ACTIVE_ENV || process.env.NODE_ENV || "development"; +if (env === "production") { + posthog.init("HR8Gte105aCHNx2BqhL1XkbvH9kzKGptxjkbhuTj6Ek", { + api_host: "https://posthog.chuckdries.com", + }); } export const onRouteUpdate = function () { - if ( - env === 'production' && - typeof window.plausible === 'object' - ) { - window.plausible('pageview'); - posthog.capture('$pageview'); + if (env === "production" && typeof window.plausible === "object") { + window.plausible("pageview"); + posthog.capture("$pageview"); } }; // import * as React from 'react'; diff --git a/gatsby-config.js b/gatsby-config.js index 70fd045..9f16039 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -1,56 +1,56 @@ module.exports = { siteMetadata: { - title: 'Chuck Dries', - siteUrl: 'https://chuckdries.com', + title: "Chuck Dries", + siteUrl: "https://chuckdries.com", }, plugins: [ - 'gatsby-plugin-sass', - 'gatsby-plugin-image', - 'gatsby-plugin-react-helmet', + "gatsby-plugin-sass", + "gatsby-plugin-image", + "gatsby-plugin-react-helmet", { - resolve: 'gatsby-plugin-manifest', + resolve: "gatsby-plugin-manifest", options: { - icon: 'src/images/glasses-outline.svg', + icon: "src/images/glasses-outline.svg", }, }, - 'gatsby-plugin-mdx', - 'gatsby-plugin-sharp', - 'gatsby-transformer-sharp', - 'gatsby-plugin-postcss', + "gatsby-plugin-mdx", + "gatsby-plugin-sharp", + "gatsby-transformer-sharp", + "gatsby-plugin-postcss", { - resolve: 'gatsby-source-filesystem', + resolve: "gatsby-source-filesystem", options: { - name: 'images', - path: './src/images/', + name: "images", + path: "./src/images/", }, - __key: 'images', + __key: "images", }, { - resolve: 'gatsby-source-filesystem', + resolve: "gatsby-source-filesystem", options: { - name: 'gallery', - path: './data/gallery/', + name: "gallery", + path: "./data/gallery/", }, - __key: 'gallery', + __key: "gallery", }, { - resolve: 'gatsby-source-filesystem', + resolve: "gatsby-source-filesystem", options: { - name: 'pages', - path: './src/pages/', + name: "pages", + path: "./src/pages/", }, - __key: 'pages', + __key: "pages", }, { - resolve: 'gatsby-plugin-eslint', + resolve: "gatsby-plugin-eslint", options: { - stages: ['develop'], - extensions: ['js', 'jsx'], - exclude: ['node_modules', '.cache', 'public'], + stages: ["develop"], + extensions: ["js", "jsx"], + exclude: ["node_modules", ".cache", "public"], // Any eslint-webpack-plugin options below }, }, - 'gatsby-plugin-preval', - 'gatsby-plugin-robots-txt', + "gatsby-plugin-preval", + "gatsby-plugin-robots-txt", ], }; diff --git a/gatsby-node.js b/gatsby-node.js index 37926c7..c05253d 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -1,12 +1,12 @@ -const fs = require('fs'); -const util = require('util'); -const path = require('path'); -const { read } = require('fast-exif'); -const iptc = require('node-iptc'); -const Vibrant = require('node-vibrant'); -const chroma = require('chroma-js'); -const chalk = require('chalk'); -const R = require('ramda'); +const fs = require("fs"); +const util = require("util"); +const path = require("path"); +const { read } = require("fast-exif"); +const iptc = require("node-iptc"); +const Vibrant = require("node-vibrant"); +const chroma = require("chroma-js"); +const chalk = require("chalk"); +const R = require("ramda"); const readFile = util.promisify(fs.readFile); @@ -15,9 +15,11 @@ const badContrast = (color1, color2) => chroma.contrast(color1, color2) < 4.5; const logColorsWithContrast = (color1, color2, text) => { const c1hex = color1.hex(); const c2hex = color2.hex(); - console.log(chalk.hex(c1hex).bgHex(c2hex)( - `${text} ${c1hex}/${c2hex} ${chroma.contrast(color1, color2)}` - )); + console.log( + chalk.hex(c1hex).bgHex(c2hex)( + `${text} ${c1hex}/${c2hex} ${chroma.contrast(color1, color2)}` + ) + ); }; function processColors(vibrantData, imagePath) { @@ -29,7 +31,10 @@ function processColors(vibrantData, imagePath) { let LightMuted = chroma(vibrantData.LightMuted.getRgb()); // first pass - darken bg and lighten relevant fg colors - if (badContrast(DarkVibrant, Vibrant) || badContrast(DarkVibrant, LightMuted)) { + if ( + badContrast(DarkVibrant, Vibrant) || + badContrast(DarkVibrant, LightMuted) + ) { DarkVibrant = DarkVibrant.darken(); if (badContrast(DarkVibrant, Vibrant)) { Vibrant = Vibrant.brighten(); @@ -39,7 +44,10 @@ function processColors(vibrantData, imagePath) { } } // second pass - first doesn't always do enough - if (badContrast(DarkVibrant, Vibrant) || badContrast(DarkVibrant, LightMuted)) { + if ( + badContrast(DarkVibrant, Vibrant) || + badContrast(DarkVibrant, LightMuted) + ) { // DarkVibrant = DarkVibrant.darken(); if (badContrast(DarkVibrant, Vibrant)) { Vibrant = Vibrant.brighten(2); @@ -49,16 +57,15 @@ function processColors(vibrantData, imagePath) { } } - if (badContrast(DarkVibrant, Vibrant)){ - console.warn('contrast still too low', imagePath); - logColorsWithContrast(Vibrant, DarkVibrant, 'V-DV'); + if (badContrast(DarkVibrant, Vibrant)) { + console.warn("contrast still too low", imagePath); + logColorsWithContrast(Vibrant, DarkVibrant, "V-DV"); } - if (badContrast(DarkVibrant, LightMuted)){ - console.warn('contrast still too low', imagePath); - logColorsWithContrast(LightMuted, DarkVibrant, 'LM-DV'); + if (badContrast(DarkVibrant, LightMuted)) { + console.warn("contrast still too low", imagePath); + logColorsWithContrast(LightMuted, DarkVibrant, "LM-DV"); } - return { Vibrant: Vibrant.rgb(), DarkVibrant: DarkVibrant.rgb(), @@ -82,25 +89,20 @@ function transformMetaToNodeData(exifData, iptcData, vibrantData, imagePath) { const gps = { longitude: null, latitude: null }; if (exifData) { - if ( - exifData.gps && - exifData.gps.GPSLongitude && - exifData.gps.GPSLatitude - ) { + if (exifData.gps && exifData.gps.GPSLongitude && exifData.gps.GPSLatitude) { gps.longitude = convertDMSToDD( exifData.gps.GPSLongitude, - exifData.gps.GPSLongitudeRef === 'E' + exifData.gps.GPSLongitudeRef === "E" ); gps.latitude = convertDMSToDD( exifData.gps.GPSLatitude, - exifData.gps.GPSLatitudeRef === 'N' + exifData.gps.GPSLatitudeRef === "N" ); } } const vibrant = vibrantData ? processColors(vibrantData, imagePath) : null; - return { exif: exifData?.exif, gps, @@ -110,10 +112,9 @@ function transformMetaToNodeData(exifData, iptcData, vibrantData, imagePath) { }; } - exports.onCreateNode = async function ({ node, actions }) { const { createNodeField } = actions; - if (node.internal.type === 'File' && node.sourceInstanceName === 'gallery') { + if (node.internal.type === "File" && node.sourceInstanceName === "gallery") { const file = await readFile(node.absolutePath); const iptcData = iptc(file); const exifData = await read(node.absolutePath); @@ -123,8 +124,13 @@ exports.onCreateNode = async function ({ node, actions }) { createNodeField({ node, - name: 'imageMeta', - value: transformMetaToNodeData(exifData, iptcData, vibrantData, node.absolutePath), + name: "imageMeta", + value: transformMetaToNodeData( + exifData, + iptcData, + vibrantData, + node.absolutePath + ), }); } }; @@ -135,45 +141,46 @@ exports.createPages = async ({ graphql, actions, reporter }) => { const { createPage } = actions; // get all images const galleryImages = await graphql(` - { - allFile(filter: { - sourceInstanceName: { eq: "gallery" }} - ) { - edges { - node { - relativePath, - base, - fields { - imageMeta { - dateTaken - } + { + allFile(filter: { sourceInstanceName: { eq: "gallery" } }) { + edges { + node { + relativePath + base + fields { + imageMeta { + dateTaken } } } } } - `); + } + `); // Handle errors if (galleryImages.errors) { - reporter.panicOnBuild('Error while running GraphQL query.'); + reporter.panicOnBuild("Error while running GraphQL query."); return; } // Create pages for each markdown file. - const galleryImageTemplate = path.resolve('src/components/GalleryImage/GalleryImage.js'); - // const diffDate = (a, b) => + const galleryImageTemplate = path.resolve( + "src/components/GalleryImage/GalleryImage.js" + ); + // const diffDate = (a, b) => // new Date(R.path(['node', 'childImageSharp', 'fields', 'imageMeta', 'dateTaken'], a)).getTime() - new Date(R.path(['node', 'childImageSharp', 'fields', 'imageMeta', 'dateTaken'],b)).getTime(); - - const edges = R.sort(R.descend((edge) => - new Date(R.path(['node', 'fields', 'imageMeta', 'dateTaken'], edge))), - galleryImages.data.allFile.edges); + + const edges = R.sort( + R.descend( + (edge) => + new Date(R.path(["node", "fields", "imageMeta", "dateTaken"], edge)) + ), + galleryImages.data.allFile.edges + ); edges.forEach(({ node }, index) => { - const nextImage = index === edges.length - 1 - ? null - : edges[index + 1].node.base; - const prevImage = index === 0 - ? null - : edges[index - 1].node.base; + const nextImage = + index === edges.length - 1 ? null : edges[index + 1].node.base; + const prevImage = index === 0 ? null : edges[index - 1].node.base; const page = { path: `photogallery/${node.base}`, component: galleryImageTemplate, diff --git a/gatsby-ssr.js b/gatsby-ssr.js index 387e300..aa2bdc3 100644 --- a/gatsby-ssr.js +++ b/gatsby-ssr.js @@ -1 +1 @@ -import './src/styles/global.css'; \ No newline at end of file +import "./src/styles/global.css"; diff --git a/package.json b/package.json index e7d9a6c..7d63a95 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "lint": "eslint --ext .jsx,.js src", "upload": "rsync -rz --delete public/ ci@droplet.chuckdries.com:www/personal-website", "upload-staging": "rsync -rz --delete public/ ci@droplet.chuckdries.com:www/personal-website-staging", - "deploy": "yarn build && yarn upload" + "deploy": "yarn build && yarn upload", + "pretty": "prettier --write ." }, "dependencies": { "@mdx-js/mdx": "^1.6.22", @@ -64,5 +65,7 @@ "tailwindcss": "^2.1.2", "use-breakpoint": "^2.0.1" }, - "devDependencies": {} + "devDependencies": { + "prettier": "2.3.2" + } } diff --git a/postcss.config.js b/postcss.config.js index 996d458..8665375 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,7 +1,7 @@ module.exports = { plugins: { tailwindcss: {}, - 'postcss-nested': {}, + "postcss-nested": {}, autoprefixer: {}, }, }; diff --git a/src/breakpoints.js b/src/breakpoints.js index 4ff08b7..97aca46 100644 --- a/src/breakpoints.js +++ b/src/breakpoints.js @@ -1,4 +1,4 @@ -import preval from 'babel-plugin-preval/macro'; +import preval from "babel-plugin-preval/macro"; const themeBreakpoints = preval` const R = require('ramda') const resolveConfig = require('tailwindcss/resolveConfig'); @@ -7,4 +7,4 @@ const {theme} = resolveConfig(tailwindConfig); module.exports = R.map(size => parseInt(size, 10), theme.screens); `; -export default themeBreakpoints; \ No newline at end of file +export default themeBreakpoints; diff --git a/src/components/GalleryImage/GalleryImage.js b/src/components/GalleryImage/GalleryImage.js index 7594e5d..785fa69 100644 --- a/src/components/GalleryImage/GalleryImage.js +++ b/src/components/GalleryImage/GalleryImage.js @@ -1,5 +1,5 @@ -import React from 'react'; -import { graphql, navigate, Link } from 'gatsby'; +import React from "react"; +import { graphql, navigate, Link } from "gatsby"; import { getAspectRatio, getMeta, @@ -8,19 +8,21 @@ import { getVibrant, getVibrantToHelmetSafeBodyStyle, hasName, -} from '../../utils'; -import { GatsbyImage, getImage } from 'gatsby-plugin-image'; -import { Helmet } from 'react-helmet'; -import classnames from 'classnames'; -import posthog from 'posthog-js'; -import MetadataItem from './MetadataItem'; +} from "../../utils"; +import { GatsbyImage, getImage } from "gatsby-plugin-image"; +import { Helmet } from "react-helmet"; +import classnames from "classnames"; +import posthog from "posthog-js"; +import MetadataItem from "./MetadataItem"; const logKeyShortcut = (keyCode) => { try { // eslint-disable-next-line - posthog.capture('[key shortcut]', { keyCode }); - window.plausible('KeyShortcut', {props: { keyCode }}); - } catch (e) {/* do nothing */} + posthog.capture("[key shortcut]", { keyCode }); + window.plausible("KeyShortcut", { props: { keyCode } }); + } catch (e) { + /* do nothing */ + } }; const GalleryImage = ({ data, pageContext }) => { @@ -29,32 +31,31 @@ const GalleryImage = ({ data, pageContext }) => { React.useEffect(() => { const keyListener = (e) => { - switch (e.code) { - case 'ArrowRight': { - logKeyShortcut(e.code); - if (pageContext.nextImage) { - navigate(`/photogallery/${pageContext.nextImage}/`); + case "ArrowRight": { + logKeyShortcut(e.code); + if (pageContext.nextImage) { + navigate(`/photogallery/${pageContext.nextImage}/`); + } + return; } - return; - } - case 'ArrowLeft': { - logKeyShortcut(e.code); - if (pageContext.prevImage) { - navigate(`/photogallery/${pageContext.prevImage}/`); + case "ArrowLeft": { + logKeyShortcut(e.code); + if (pageContext.prevImage) { + navigate(`/photogallery/${pageContext.prevImage}/`); + } + return; + } + case "Escape": + case "KeyG": { + logKeyShortcut(e.code); + navigate("/photogallery/"); } - return; - } - case 'Escape': - case 'KeyG': { - logKeyShortcut(e.code); - navigate('/photogallery/'); - } } }; - document.addEventListener('keydown', keyListener); + document.addEventListener("keydown", keyListener); return () => { - document.removeEventListener('keydown', keyListener); + document.removeEventListener("keydown", keyListener); }; }, [pageContext]); @@ -62,128 +63,193 @@ const GalleryImage = ({ data, pageContext }) => { const meta = getMeta(image); let locationString; if (meta.iptc.city || meta.iptc.province_or_state) { - const location = [meta.iptc.city, meta.iptc.province_or_state].filter(Boolean); - locationString = location.join(', '); + const location = [meta.iptc.city, meta.iptc.province_or_state].filter( + Boolean + ); + locationString = location.join(", "); } const vibrant = getVibrant(image, true); - const orientationClasses = ar > 1 ? 'flex-col mx-auto' : 'portrait:mx-auto landscape:mx-5 landscape:flex-row-reverse portrait:flex-col'; - const shutterSpeed = React.useMemo(() => getShutterFractionFromExposureTime(meta.exif.ExposureTime || 0), [meta]); + const orientationClasses = + ar > 1 + ? "flex-col mx-auto" + : "portrait:mx-auto landscape:mx-5 landscape:flex-row-reverse portrait:flex-col"; + const shutterSpeed = React.useMemo( + () => getShutterFractionFromExposureTime(meta.exif.ExposureTime || 0), + [meta] + ); const dateTaken = React.useMemo(() => new Date(meta.dateTaken), [meta]); - return (<> - <Helmet> - <title>{name} - Gallery | Chuck Dries</title> - <body - className="text-vibrant-light bg-vibrant-dark" - style={getVibrantToHelmetSafeBodyStyle(vibrant)} - /> - </Helmet> - <div className="min-h-screen flex flex-col justify-between"> - <nav className="mt-1 ml-1 text-lg mb-4"> - <button - className="hover:underline text-vibrant-light hover:text-muted-light arrow-left-before mr-1" - onClick={() => navigate(-1)} - type="button" - >back</button> - <Link - className="hover:underline text-vibrant-light hover:text-muted-light mx-1" - to="/" - >home</Link> - <Link - className="hover:underline text-vibrant-light hover:text-muted-light mx-1" - to="/photogallery/" - >gallery <span className="bg-gray-300 text-black">esc</span></Link> - {pageContext.prevImage && <Link - className="hover:underline text-vibrant-light hover:text-muted-light mx-1" - to={`/photogallery/${pageContext.prevImage}/`} - >previous <span className="bg-gray-300 text-black">⭠</span></Link>} - {pageContext.nextImage && <Link - className="hover:underline text-vibrant-light hover:text-muted-light mx-1" - to={`/photogallery/${pageContext.nextImage}/`} - >next <span className="bg-gray-300 text-black">⭢</span></Link>} - </nav> - <div className={classnames('flex', orientationClasses)}> - <div className="flex-grow-0"> - <GatsbyImage - alt={name} - className="" - image={getImage(image)} - key={image.base} - loading="eager" - objectFit="contain" - style={{ - maxWidth: `calc(max(90vh, 500px) * ${ar})`, - maxHeight: '90vh', - // minHeight: '500px', - }} /> - </div> - <div className={classnames( - 'flex-shrink-0 mx-2 flex flex-row portrait:items-end', ar <= 1 - ? 'pt-5 flex-col flex-auto text-right' - : 'portrait:pt-5 portrait:flex-col portrait:text-right' - )}> - <div className="flex-auto mr-2"> - <p className="text-muted-light font-mono text-sm m-0 mt-1">{image.base}</p> - {hasName(image) && <h1 className="text-4xl mt-0 font-serif">{name}</h1>} - <p className="landscape:mr-2">{meta.iptc.caption}</p> + return ( + <> + <Helmet> + <title>{name} - Gallery | Chuck Dries</title> + <body + className="text-vibrant-light bg-vibrant-dark" + style={getVibrantToHelmetSafeBodyStyle(vibrant)} + /> + </Helmet> + <div className="min-h-screen flex flex-col justify-between"> + <nav className="mt-1 ml-1 text-lg mb-4"> + <button + className="hover:underline text-vibrant-light hover:text-muted-light arrow-left-before mr-1" + onClick={() => navigate(-1)} + type="button" + > + back + </button> + <Link + className="hover:underline text-vibrant-light hover:text-muted-light mx-1" + to="/" + > + home + </Link> + <Link + className="hover:underline text-vibrant-light hover:text-muted-light mx-1" + to="/photogallery/" + > + gallery <span className="bg-gray-300 text-black">esc</span> + </Link> + {pageContext.prevImage && ( + <Link + className="hover:underline text-vibrant-light hover:text-muted-light mx-1" + to={`/photogallery/${pageContext.prevImage}/`} + > + previous <span className="bg-gray-300 text-black">⭠</span> + </Link> + )} + {pageContext.nextImage && ( + <Link + className="hover:underline text-vibrant-light hover:text-muted-light mx-1" + to={`/photogallery/${pageContext.nextImage}/`} + > + next <span className="bg-gray-300 text-black">⭢</span> + </Link> + )} + </nav> + <div className={classnames("flex", orientationClasses)}> + <div className="flex-grow-0"> + <GatsbyImage + alt={name} + className="" + image={getImage(image)} + key={image.base} + loading="eager" + objectFit="contain" + style={{ + maxWidth: `calc(max(90vh, 500px) * ${ar})`, + maxHeight: "90vh", + // minHeight: '500px', + }} + /> + </div> + <div + className={classnames( + "flex-shrink-0 mx-2 flex flex-row portrait:items-end", + ar <= 1 + ? "pt-5 flex-col flex-auto text-right" + : "portrait:pt-5 portrait:flex-col portrait:text-right" + )} + > + <div className="flex-auto mr-2"> + <p className="text-muted-light font-mono text-sm m-0 mt-1"> + {image.base} + </p> + {hasName(image) && ( + <h1 className="text-4xl mt-0 font-serif">{name}</h1> + )} + <p className="landscape:mr-2">{meta.iptc.caption}</p> + </div> + { + <div + className="portrait:border-t-2 border-muted-light portrait:mt-2 mr-2 portrait:mb-1" + style={{ width: 30 }} + ></div> + } + <MetadataItem + aspectRatio={ar} + data={dateTaken.toLocaleDateString()} + icon="calendar-sharp" + title="date taken" + /> + <MetadataItem + aspectRatio={ar} + data={locationString} + icon="location-sharp" + title="location" + /> + <MetadataItem + aspectRatio={ar} + data={shutterSpeed} + icon="stopwatch-sharp" + title="shutter speed" + /> + <MetadataItem + aspectRatio={ar} + data={`f/${meta.exif.FNumber}`} + icon="aperture-sharp" + title="aperture" + /> + <MetadataItem + aspectRatio={ar} + data={meta.exif.ISO} + icon="film-outline" + title="ISO" + /> </div> - {<div className="portrait:border-t-2 border-muted-light portrait:mt-2 mr-2 portrait:mb-1" style={{width: 30}}></div>} - <MetadataItem aspectRatio={ar} data={dateTaken.toLocaleDateString()} icon="calendar-sharp" title="date taken"/> - <MetadataItem aspectRatio={ar} data={locationString} icon="location-sharp" title="location"/> - <MetadataItem aspectRatio={ar} data={shutterSpeed} icon="stopwatch-sharp" title="shutter speed" /> - <MetadataItem aspectRatio={ar} data={`f/${meta.exif.FNumber}`} icon="aperture-sharp" title="aperture" /> - <MetadataItem aspectRatio={ar} data={meta.exif.ISO} icon="film-outline" title="ISO" /> </div> + <div></div> </div> - <div></div> - </div> - </>); + </> + ); }; export const query = graphql` query GalleryImage($imageFilename: String) { - allFile(filter: {sourceInstanceName: {eq: "gallery"}, base: {eq: $imageFilename}}) { - edges { - node { - base - childImageSharp{ - fluid { - aspectRatio + allFile( + filter: { + sourceInstanceName: { eq: "gallery" } + base: { eq: $imageFilename } + } + ) { + edges { + node { + base + childImageSharp { + fluid { + aspectRatio + } + gatsbyImageData( + layout: CONSTRAINED + # placeholder: BLURRED + placeholder: DOMINANT_COLOR + # placeholder: TRACED_SVG + height: 2160 + ) } - gatsbyImageData( - layout: CONSTRAINED - # placeholder: BLURRED - placeholder: DOMINANT_COLOR - # placeholder: TRACED_SVG - height: 2160 - ) - } - fields { - imageMeta { - dateTaken - iptc { - caption - object_name - keywords - city - province_or_state - } - exif { - FNumber - ExposureTime - ISO - } - vibrant { - ...VibrantColors + fields { + imageMeta { + dateTaken + iptc { + caption + object_name + keywords + city + province_or_state + } + exif { + FNumber + ExposureTime + ISO + } + vibrant { + ...VibrantColors + } } } } } } } -} - - `; export default GalleryImage; diff --git a/src/components/GalleryImage/MetadataItem.js b/src/components/GalleryImage/MetadataItem.js index cb077e8..88ec1da 100644 --- a/src/components/GalleryImage/MetadataItem.js +++ b/src/components/GalleryImage/MetadataItem.js @@ -1,21 +1,20 @@ -import classNames from 'classnames'; -import React from 'react'; +import classNames from "classnames"; +import React from "react"; -const MetadataItem = ({ - aspectRatio, - icon, - data, - title, -}) => data ? ( - <div className={classNames('flex items-baseline ml-2 text-lg', - aspectRatio <= 1 ? 'flex-row-reverse' : 'portrait:flex-row-reverse')} - title={title} - > - <span className="icon-offset mr-1"> - <ion-icon name={icon}></ion-icon> - </span> - <span className="mr-1">{data}</span> - </div> -) : null; +const MetadataItem = ({ aspectRatio, icon, data, title }) => + data ? ( + <div + className={classNames( + "flex items-baseline ml-2 text-lg", + aspectRatio <= 1 ? "flex-row-reverse" : "portrait:flex-row-reverse" + )} + title={title} + > + <span className="icon-offset mr-1"> + <ion-icon name={icon}></ion-icon> + </span> + <span className="mr-1">{data}</span> + </div> + ) : null; -export default MetadataItem; \ No newline at end of file +export default MetadataItem; diff --git a/src/components/Index/HeroLink.js b/src/components/Index/HeroLink.js index e3a5044..c9359db 100644 --- a/src/components/Index/HeroLink.js +++ b/src/components/Index/HeroLink.js @@ -1,5 +1,5 @@ -import * as React from 'react'; -import classnames from 'classnames'; +import * as React from "react"; +import classnames from "classnames"; export const HeroA = ({ href, @@ -9,8 +9,14 @@ export const HeroA = ({ ...linkProps }) => ( <a - className={classnames('mx-2 underline', isClient && 'text-muted-light hover:text-vibrant-light', className)} + className={classnames( + "mx-2 underline", + isClient && "text-muted-light hover:text-vibrant-light", + className + )} href={href} {...linkProps} - >{children}</a> -); \ No newline at end of file + > + {children} + </a> +); diff --git a/src/components/MasonryGallery.js b/src/components/MasonryGallery.js index b79c072..69a3446 100644 --- a/src/components/MasonryGallery.js +++ b/src/components/MasonryGallery.js @@ -1,33 +1,41 @@ -import * as React from 'react'; -import { Link } from 'gatsby'; -import { GatsbyImage, getImage } from 'gatsby-plugin-image'; -import * as R from 'ramda'; -import { getAspectRatio, getName } from '../utils'; -import useBreakpoint from 'use-breakpoint'; +import * as React from "react"; +import { Link } from "gatsby"; +import { GatsbyImage, getImage } from "gatsby-plugin-image"; +import * as R from "ramda"; +import { getAspectRatio, getName } from "../utils"; +import useBreakpoint from "use-breakpoint"; -import themeBreakpoints from '../breakpoints'; +import themeBreakpoints from "../breakpoints"; const MasonryGallery = ({ images, itemsPerRow: itemsPerRowByBreakpoint }) => { - const breakpoints = React.useMemo(() => - R.pick(R.keys(itemsPerRowByBreakpoint), themeBreakpoints) - , [itemsPerRowByBreakpoint]); + const breakpoints = React.useMemo( + () => R.pick(R.keys(itemsPerRowByBreakpoint), themeBreakpoints), + [itemsPerRowByBreakpoint] + ); - const { breakpoint } = useBreakpoint(breakpoints, 'sm'); + const { breakpoint } = useBreakpoint(breakpoints, "sm"); - const aspectRatios = React.useMemo(() => R.map(getAspectRatio, images), [images]); - const rowAspectRatioSumsByBreakpoint = React.useMemo(() => R.map(R.pipe( - R.splitEvery(R.__, aspectRatios), - R.map(R.sum) - ))(itemsPerRowByBreakpoint), [aspectRatios, itemsPerRowByBreakpoint]); + const aspectRatios = React.useMemo( + () => R.map(getAspectRatio, images), + [images] + ); + const rowAspectRatioSumsByBreakpoint = React.useMemo( + () => + R.map(R.pipe(R.splitEvery(R.__, aspectRatios), R.map(R.sum)))( + itemsPerRowByBreakpoint + ), + [aspectRatios, itemsPerRowByBreakpoint] + ); const itemsPerRow = itemsPerRowByBreakpoint[breakpoint]; - const rowAspectRatioSumsForCurrentBP = rowAspectRatioSumsByBreakpoint[breakpoint]; - + const rowAspectRatioSumsForCurrentBP = + rowAspectRatioSumsByBreakpoint[breakpoint]; + return ( <div className="w-full" style={{ - position: 'relative', + position: "relative", }} // style={{ maxWidth: minWidth }} > @@ -36,22 +44,24 @@ const MasonryGallery = ({ images, itemsPerRow: itemsPerRowByBreakpoint }) => { const rowAspectRatioSum = rowAspectRatioSumsForCurrentBP[rowIndex]; // const width = ((getAspectRatio(image) / rowAspectRatioSum) * 100).toFixed(10); const ar = getAspectRatio(image); - const widthNumber = rowAspectRatioSum === ar - // image is only one in row - ? 100 / itemsPerRow - // image is one of several in row - : ((ar / rowAspectRatioSum) * 100).toFixed(5); + const widthNumber = + rowAspectRatioSum === ar + ? // image is only one in row + 100 / itemsPerRow + : // image is one of several in row + ((ar / rowAspectRatioSum) * 100).toFixed(5); const width = `${widthNumber}%`; return ( - <Link + <Link className="inline-block" key={`${image.base}`} - state={{modal: true}} + state={{ modal: true }} style={{ width, // marginLeft: '8px', - }} to={`/photogallery/${image.base}`} + }} + to={`/photogallery/${image.base}`} > <GatsbyImage alt={getName(image)} @@ -63,7 +73,8 @@ const MasonryGallery = ({ images, itemsPerRow: itemsPerRowByBreakpoint }) => { </Link> ); })} - </div>); + </div> + ); // return null; }; diff --git a/src/components/resume/ResumeLayout.js b/src/components/resume/ResumeLayout.js index e211436..2d57584 100644 --- a/src/components/resume/ResumeLayout.js +++ b/src/components/resume/ResumeLayout.js @@ -1,10 +1,10 @@ -import * as React from 'react'; -import classnames from 'classnames'; -import { MDXProvider } from '@mdx-js/react'; +import * as React from "react"; +import classnames from "classnames"; +import { MDXProvider } from "@mdx-js/react"; -import '../../styles/resume.css'; +import "../../styles/resume.css"; -const MyH1 = props => <h1 style={{ color: 'tomato' }} {...props} />; +const MyH1 = (props) => <h1 style={{ color: "tomato" }} {...props} />; // const MyParagraph = props => ( // <p style={{ fontSize: '18px', lineHeight: 1.6 }} {...props} /> // ); @@ -14,12 +14,13 @@ const components = { // p: MyParagraph, }; - const ResumeLayout = ({ pageContext, children }) => { - console.log('pc', pageContext); + console.log("pc", pageContext); return ( <MDXProvider components={components}> - <div className={classnames('font-serif container mx-auto resume')}>{children}</div> + <div className={classnames("font-serif container mx-auto resume")}> + {children} + </div> </MDXProvider> ); }; diff --git a/src/fragments.js b/src/fragments.js index a258faf..a1782ef 100644 --- a/src/fragments.js +++ b/src/fragments.js @@ -1,4 +1,4 @@ -import { graphql } from 'gatsby'; +import { graphql } from "gatsby"; export const VibrantColorsFragment = graphql` fragment VibrantColors on FileFieldsImageMetaVibrant { @@ -9,4 +9,4 @@ export const VibrantColorsFragment = graphql` Vibrant Muted } -`; \ No newline at end of file +`; diff --git a/src/html.js b/src/html.js index e4e3a7f..29a6594 100644 --- a/src/html.js +++ b/src/html.js @@ -1,7 +1,8 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import React from "react"; +import PropTypes from "prop-types"; -const env = process.env.GATSBY_ACTIVE_ENV || process.env.NODE_ENV || 'development'; +const env = + process.env.GATSBY_ACTIVE_ENV || process.env.NODE_ENV || "development"; export default function HTML(props) { return ( @@ -9,25 +10,40 @@ export default function HTML(props) { <head> <meta charSet="utf-8" /> <meta content="ie=edge" httpEquiv="x-ua-compatible" /> - <meta content="Chuck Dries: Full Stack Software Engineer and Photographer" name="description" /> + <meta + content="Chuck Dries: Full Stack Software Engineer and Photographer" + name="description" + /> <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport" /> {props.headComponents} - {env === 'production' && <script async data-domain="chuckdries.com" defer src="https://analytics.chuckdries.com/js/plausible.js"></script>} + {env === "production" && ( + <script + async + data-domain="chuckdries.com" + defer + src="https://analytics.chuckdries.com/js/plausible.js" + ></script> + )} {/* eslint-disable-next-line */} - {env === 'production' && <script>{`window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }`}</script>} + {env === "production" && ( + <script>{`window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }`}</script> + )} </head> <body {...props.bodyAttributes}> {props.preBodyComponents} <div dangerouslySetInnerHTML={{ __html: props.body }} id="___gatsby" - key={'body'} + key={"body"} /> {props.postBodyComponents} - <script src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.esm.js" type="module"></script> + <script + src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.esm.js" + type="module" + ></script> </body> </html> ); diff --git a/src/pages/404.js b/src/pages/404.js index 16abeea..5b0d2ef 100644 --- a/src/pages/404.js +++ b/src/pages/404.js @@ -1,11 +1,11 @@ -import * as React from 'react'; -import { Link } from 'gatsby'; +import * as React from "react"; +import { Link } from "gatsby"; // styles const pageStyles = { - color: '#232129', - padding: '96px', - fontFamily: '-apple-system, Roboto, sans-serif, serif', + color: "#232129", + padding: "96px", + fontFamily: "-apple-system, Roboto, sans-serif, serif", }; const headingStyles = { marginTop: 0, @@ -17,10 +17,10 @@ const paragraphStyles = { marginBottom: 48, }; const codeStyles = { - color: '#8A6534', + color: "#8A6534", padding: 4, - backgroundColor: '#FFF4DB', - fontSize: '1.25rem', + backgroundColor: "#FFF4DB", + fontSize: "1.25rem", borderRadius: 4, }; @@ -31,13 +31,13 @@ const NotFoundPage = () => { <title>Not found</title> <h1 style={headingStyles}>Page not found</h1> <p style={paragraphStyles}> - Sorry{' '} + Sorry{" "} <span aria-label="Pensive emoji" role="img"> 😔 - </span>{' '} + </span>{" "} we couldn’t find what you were looking for. <br /> - {process.env.NODE_ENV === 'development' ? ( + {process.env.NODE_ENV === "development" ? ( <> <br /> Try creating a page in <code style={codeStyles}>src/pages/</code>. diff --git a/src/pages/asdf-resume.mdx b/src/pages/asdf-resume.mdx index 34607a8..996738a 100644 --- a/src/pages/asdf-resume.mdx +++ b/src/pages/asdf-resume.mdx @@ -2,8 +2,8 @@ title: Charles Dries Resume --- -import ResumeLayout from '../components/resume/ResumeLayout' -export default ResumeLayout +import ResumeLayout from "../components/resume/ResumeLayout"; +export default ResumeLayout; # Hello, World! diff --git a/src/pages/index.js b/src/pages/index.js index de031a8..4b487ff 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -175,7 +175,7 @@ const IndexPage = ({ title="view image details" to={`/photogallery/${image.base}/`} > - <span className="icon-offset"><ion-icon name="image"></ion-icon></span> + Photography Gallery </Link> <button className={classnames( @@ -191,7 +191,7 @@ const IndexPage = ({ <span className="icon-offset"><ion-icon name="shuffle"></ion-icon></span> </button> </div> - <Link + <section className={classnames( 'hover:underline p-3 px-5 py-4 my-3 text-md sm:text-lg rounded-md border-2 arrow-right-after font-bold font-serif', isClient && 'text-muted-dark bg-muted-light bg-opacity-70 border-muted-dark hover:bg-muted')} diff --git a/src/pages/photogallery.js b/src/pages/photogallery.js index 3d5bb9c..759038c 100644 --- a/src/pages/photogallery.js +++ b/src/pages/photogallery.js @@ -1,87 +1,95 @@ -import * as React from 'react'; -import { graphql, Link } from 'gatsby'; -import { navigate } from 'gatsby'; -import { Helmet } from 'react-helmet'; +import * as React from "react"; +import { graphql, Link } from "gatsby"; +import { navigate } from "gatsby"; +import { Helmet } from "react-helmet"; -import MasonryGallery from '../components/MasonryGallery'; +import MasonryGallery from "../components/MasonryGallery"; // TODO: caption and title more images // TODO: more images const GalleryPage = ({ data }) => { - const images = React.useMemo(() => - data.allFile.edges - .map(edge => edge.node, [data]) - , [data]); + const images = React.useMemo( + () => data.allFile.edges.map((edge) => edge.node, [data]), + [data] + ); - return (<> - <Helmet> - <title>Photo Gallery | Chuck Dries</title> - <body className="bg-black text-white" /> - </Helmet> - <nav className="mt-1 ml-1 text-lg mb-4"> - <button - className="hover:underline text-vibrant-light hover:text-muted-light arrow-left-before mr-1" - onClick={() => navigate(-1)} - type="button" - >back</button> - <Link - className="hover:underline text-vibrant-light hover:text-muted-light mx-1" - to="/" - >home</Link> - <Link - className="hover:underline text-vibrant-light hover:text-muted-light mx-1" - to="/photogallery/" - >gallery</Link> - </nav> - <div className="bg-black min-h-screen mx-auto 2xl:container"> - <h1 className="text-5xl mt-0 ml-5 font-serif font-black z-10 relative">Photo Gallery</h1> - <div className="mx-auto"> - <MasonryGallery - images={images} - itemsPerRow={{ - sm: 2, - md: 2, - lg: 3, - xl: 3, - '2xl': 4, - }} - /> + return ( + <> + <Helmet> + <title>Photo Gallery | Chuck Dries</title> + <body className="bg-black text-white" /> + </Helmet> + <nav className="mt-1 ml-1 text-lg mb-4"> + <button + className="hover:underline text-vibrant-light hover:text-muted-light arrow-left-before mr-1" + onClick={() => navigate(-1)} + type="button" + > + back + </button> + <Link + className="hover:underline text-vibrant-light hover:text-muted-light mx-1" + to="/" + > + home + </Link> + <Link + className="hover:underline text-vibrant-light hover:text-muted-light mx-1" + to="/photogallery/" + > + gallery + </Link> + </nav> + <div className="bg-black min-h-screen mx-auto 2xl:container"> + <h1 className="text-5xl mt-0 ml-5 font-serif font-black z-10 relative"> + Photo Gallery + </h1> + <div className="mx-auto"> + <MasonryGallery + images={images} + itemsPerRow={{ + sm: 2, + md: 2, + lg: 3, + xl: 3, + "2xl": 4, + }} + /> + </div> </div> - </div> - </>); + </> + ); }; export const query = graphql` -query GalleryPageQuery { - allFile( - filter: { sourceInstanceName: { eq: "gallery" } } - sort: {order: DESC, fields: fields___imageMeta___dateTaken} - ) { - edges { - node { - relativePath - base - childImageSharp{ - fluid { - aspectRatio + query GalleryPageQuery { + allFile( + filter: { sourceInstanceName: { eq: "gallery" } } + sort: { order: DESC, fields: fields___imageMeta___dateTaken } + ) { + edges { + node { + relativePath + base + childImageSharp { + fluid { + aspectRatio + } + gatsbyImageData(layout: CONSTRAINED, height: 550) } - gatsbyImageData( - layout: CONSTRAINED - height: 550 - ) - } - fields { - imageMeta { - dateTaken - iptc { - object_name + fields { + imageMeta { + dateTaken + iptc { + object_name + } } } } } } } -}`; +`; export default GalleryPage; diff --git a/src/styles/global.css b/src/styles/global.css index bb660c4..a1a7dad 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -1,6 +1,6 @@ /* @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital@0;1&display=swap'); */ /* black, bold, regular */ -@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;0,900;1,400;1,700;1,900&display=swap'); +@import url("https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;0,900;1,400;1,700;1,900&display=swap"); @tailwind base; @tailwind components; @@ -30,7 +30,7 @@ scroll-snap-align: start; } .scroll-padding-6 { - scroll-padding: theme('spacing.6'); + scroll-padding: theme("spacing.6"); } .blurred-or-opaque-bg-1 { @apply bg-opacity-80; @@ -77,7 +77,7 @@ a { margin-left: 3px; transform: translate(0px); display: inline-block; - transition: all .2s; + transition: all 0.2s; } .arrow-left-before:before { diff --git a/src/styles/resume.css b/src/styles/resume.css index 94711bd..b54eff5 100644 --- a/src/styles/resume.css +++ b/src/styles/resume.css @@ -3,4 +3,3 @@ @apply text-3xl font-bold; } } - diff --git a/src/utils.js b/src/utils.js index 5dcbd08..ac2d33e 100644 --- a/src/utils.js +++ b/src/utils.js @@ -2,31 +2,36 @@ export const getMeta = (image) => image.fields.imageMeta; -export const getName = (image) => getMeta(image)?.iptc.object_name || image.base; +export const getName = (image) => + getMeta(image)?.iptc.object_name || image.base; // some pleasing default colors for SSR and initial hydration export const getVibrant = (image) => getMeta(image)?.vibrant; export const hasName = (image) => Boolean(getMeta(image)?.iptc.object_name); -export const getAspectRatio = (image) => image.childImageSharp.fluid.aspectRatio; +export const getAspectRatio = (image) => + image.childImageSharp.fluid.aspectRatio; -export const getRgba = (palette, alpha) => `rgba(${palette[0]}, ${palette[1]}, ${palette[2]}, ${alpha || 1})`; +export const getRgba = (palette, alpha) => + `rgba(${palette[0]}, ${palette[1]}, ${palette[2]}, ${alpha || 1})`; // work around SSR bug in react-helmet export const getVibrantToHelmetSafeBodyStyle = (vibrant) => { const style = { - '--muted': vibrant.Muted, - '--dark-muted': vibrant.DarkMuted, - '--light-muted': vibrant.LightMuted, - '--vibrant': vibrant.Vibrant, - '--dark-vibrant': vibrant.DarkVibrant, - '--light-vibrant': vibrant.LightVibrant, + "--muted": vibrant.Muted, + "--dark-muted": vibrant.DarkMuted, + "--light-muted": vibrant.LightMuted, + "--vibrant": vibrant.Vibrant, + "--dark-vibrant": vibrant.DarkVibrant, + "--light-vibrant": vibrant.LightVibrant, }; - if (typeof window === 'undefined') { + if (typeof window === "undefined") { return style; } - return Object.keys(style).map(key => `${(key)}: ${style[key]}`).join(';'); + return Object.keys(style) + .map((key) => `${key}: ${style[key]}`) + .join(";"); }; const gcd = (a, b) => { @@ -40,12 +45,12 @@ const gcd = (a, b) => { export const getShutterFractionFromExposureTime = (exposureTime) => { let fraction = exposureTime; const len = fraction.toString().length - 2; - + let denominator = Math.pow(10, len); let numerator = fraction * denominator; - + const divisor = gcd(numerator, denominator); - + numerator /= divisor; denominator /= divisor; return `${numerator}/${denominator}`; diff --git a/static/editme.html b/static/editme.html index 0611faf..b9d6713 100644 --- a/static/editme.html +++ b/static/editme.html @@ -6,7 +6,8 @@ <body> <h1>contenteditable can be applied to visible style tags</h1> <p contenteditable="true"> - This paragraph is editable, as is the style tag below. Edit it to see the layout change in real time. + This paragraph is editable, as is the style tag below. Edit it to see the + layout change in real time. </p> <pre> <style contenteditable="true"> diff --git a/static/game.html b/static/game.html index b8853db..be0aee0 100644 --- a/static/game.html +++ b/static/game.html @@ -1,124 +1,119 @@ <!DOCTYPE html> <html lang="en"> - -<head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <meta http-equiv="X-UA-Compatible" content="ie=edge"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Test Canvas Game</title> <style> - body { - margin: 0; - padding: 0; - } + body { + margin: 0; + padding: 0; + } </style> -</head> + </head> -<body> - <canvas id="gc"> - </canvas> + <body> + <canvas id="gc"> </canvas> <script> - //setup - c = document.getElementById("gc"); - cc = c.getContext('2d'); - c.height = window.innerHeight; - c.width = window.innerWidth; - c.addEventListener('mousemove', function(e) { - p1y = e.clientY - ph / 2; - }); + //setup + c = document.getElementById("gc"); + cc = c.getContext("2d"); + c.height = window.innerHeight; + c.width = window.innerWidth; + c.addEventListener("mousemove", function (e) { + p1y = e.clientY - ph / 2; + }); - lastTime = Date.now(); - deltaTime = 0; - fps = 0; + lastTime = Date.now(); + deltaTime = 0; + fps = 0; - //gameplay variables - p1y = p2y = 40; - pt = 10; - ph = 100; - bx = by = xv = yv = 500;//just making sure bx and by exist, they'll be reset when the game first starts - bd = 12; - score1 = score2 = 0; - ais = 5; + //gameplay variables + p1y = p2y = 40; + pt = 10; + ph = 100; + bx = by = xv = yv = 500; //just making sure bx and by exist, they'll be reset when the game first starts + bd = 12; + score1 = score2 = 0; + ais = 5; + function reset() { + bx = c.width / 2; + by = c.height / 2; + xv = -xv; + yv = 4; + } - - function reset() { - bx = c.width / 2; - by = c.height / 2; + function update() { + //measure timing + now = Date.now(); + deltaTime = (now - lastTime) / 1000; + lastTime = now; + fps = 1 / deltaTime; + //move ball + bx += xv * deltaTime; + by += yv * deltaTime; + if (by < 0 && yv < 0) { + yv = -yv; + } + if (by > c.height && yv > 0) { + yv = -yv; + } + //check collision with sides for scoring + if (bx > c.width) { + if (by > p2y && by < p2y + ph) { xv = -xv; - yv = 4; + dy = by - (p2y + ph / 2); + yv = dy * 10; + } else { + score1++; + reset(); + } } - - function update() { - //measure timing - now = Date.now(); - deltaTime = (now-lastTime)/1000; - lastTime = now; - fps = 1/deltaTime; - //move ball - bx += xv * deltaTime; - by += yv * deltaTime; - if (by < 0 && yv < 0) { - yv = -yv; - } - if (by > c.height && yv > 0) { - yv = -yv; - } - //check collision with sides for scoring - if (bx > c.width) { - if (by > p2y && by < p2y + ph) { - xv = -xv; - dy = by - (p2y + ph / 2); - yv = dy * 10; - } else { - score1++; - reset(); - } - } - if (bx < 0) { - if (by > p1y && by < p1y + ph) { - xv = -xv; - dy = by - (p1y + ph / 2); - yv = dy * 10;//.3 - } else { - score2++ - reset(); - } - } - //ai - if (p2y + ph / 2 < by) { - p2y += ais; - } else { - p2y -= ais; - } - //draw background - var gradient=cc.createLinearGradient(0,0,c.width,c.height); - gradient.addColorStop("0","#ff146e"); - gradient.addColorStop("1","#145aff"); - cc.fillStyle=gradient; -// cc.fillStyle="white"; - cc.fillRect(0, 0, c.width, c.height); - //draw paddles - cc.fillStyle = 'cyan'; - cc.fillRect(0, p1y, pt, ph); - cc.fillStyle = 'red'; - cc.fillRect(c.width - pt, p2y, pt, ph); - //draw ball - cc.fillStyle = 'lightgreen'; - cc.fillRect(bx - bd / 2, by - bd / 2, bd, bd); - //draw scores - cc.fillStyle = 'white'; - cc.font = '20px Times' - cc.fillText(score1, 100, 100); - cc.fillText(score2, c.width - 100, 100); - //draw framerate - cc.fillText("framerate: " + fps, c.width/2 - 100, 100); - - window.requestAnimationFrame(update); //Keep the game running + if (bx < 0) { + if (by > p1y && by < p1y + ph) { + xv = -xv; + dy = by - (p1y + ph / 2); + yv = dy * 10; //.3 + } else { + score2++; + reset(); + } } - reset() //prepare the game - update() //start the game + //ai + if (p2y + ph / 2 < by) { + p2y += ais; + } else { + p2y -= ais; + } + //draw background + var gradient = cc.createLinearGradient(0, 0, c.width, c.height); + gradient.addColorStop("0", "#ff146e"); + gradient.addColorStop("1", "#145aff"); + cc.fillStyle = gradient; + // cc.fillStyle="white"; + cc.fillRect(0, 0, c.width, c.height); + //draw paddles + cc.fillStyle = "cyan"; + cc.fillRect(0, p1y, pt, ph); + cc.fillStyle = "red"; + cc.fillRect(c.width - pt, p2y, pt, ph); + //draw ball + cc.fillStyle = "lightgreen"; + cc.fillRect(bx - bd / 2, by - bd / 2, bd, bd); + //draw scores + cc.fillStyle = "white"; + cc.font = "20px Times"; + cc.fillText(score1, 100, 100); + cc.fillText(score2, c.width - 100, 100); + //draw framerate + cc.fillText("framerate: " + fps, c.width / 2 - 100, 100); + + window.requestAnimationFrame(update); //Keep the game running + } + reset(); //prepare the game + update(); //start the game </script> -</body> - + </body> </html> diff --git a/static/learn.html b/static/learn.html index 028cd7a..4b308b9 100644 --- a/static/learn.html +++ b/static/learn.html @@ -1,19 +1,16 @@ -<!DOCTYPE html> -<html lang="en"> - -<head> - <meta charset="UTF-8"> - <title>Document</title> - <link rel="stylesheet" href="link/to/css"> -</head> - -<body> - <a href="">a tags are for links</a> - <p>p tags are for paragraphs</p> - <h1>h1 through h6 are for headers</h1> - <img src="path/to/image.jpg" alt="imgs are for images"> - <div>divs are just boxes</div> - -</body> - -</html> \ No newline at end of file +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <title>Document</title> + <link rel="stylesheet" href="link/to/css" /> + </head> + + <body> + <a href="">a tags are for links</a> + <p>p tags are for paragraphs</p> + <h1>h1 through h6 are for headers</h1> + <img src="path/to/image.jpg" alt="imgs are for images" /> + <div>divs are just boxes</div> + </body> +</html> diff --git a/static/roboticchuck.html b/static/roboticchuck.html index 53ae0ef..1e2c063 100644 --- a/static/roboticchuck.html +++ b/static/roboticchuck.html @@ -1,77 +1,101 @@ <!DOCTYPE html> <html lang="en"> - -<head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <meta http-equiv="X-UA-Compatible" content="ie=edge"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Robotic Chuck</title> <style> - body { - margin: auto; - max-width: 800px; - line-height: 1.5; - } - - code, - #output { - padding: 5px; - background: #eee; - border: 1px solid #ccc; - border-radius: 3px; - display: inline-block; - } - - p { - max-width: 800px; - } - - input, - textarea { - width: 100%; - padding: 5px; - /*max-width: 800px;*/ - } - - #genbutton { - color: white; - background: #01C106; - padding: 1em; - border: 1px solid #1E7931; - font-size: 1em; - border-radius: 3px; - } - </style> -</head> + body { + margin: auto; + max-width: 800px; + line-height: 1.5; + } -<body> + code, + #output { + padding: 5px; + background: #eee; + border: 1px solid #ccc; + border-radius: 3px; + display: inline-block; + } + + p { + max-width: 800px; + } + + input, + textarea { + width: 100%; + padding: 5px; + /*max-width: 800px;*/ + } + + #genbutton { + color: white; + background: #01c106; + padding: 1em; + border: 1px solid #1e7931; + font-size: 1em; + border-radius: 3px; + } + </style> + </head> + + <body> <script> - console.log("load"); - function generate() { - console.log("go!"); - var inBox = document.getElementById("in"); - console.log(inBox.value); - var links = JSON.parse(inBox.value); - var outBox = document.getElementById("output"); - var titleBox = document.getElementById("titleIn"); - var descBox = document.getElementById("description"); - var tstring = "<style>.here,.invmenu a{font-style:italic}.here{font-size:14px;font-weight:400;color:grey}.invmenu{padding:5px 20px;margin:10px 0}</style>\n"; - tstring = tstring + "<" + "div class=\"invmenu\" style=\"max-width:100%;background: #f2f2f2;\">\n<h3 style=\"text-align:left;\">" + titleBox.value + "</h3>\n<p><em>"; - tstring = tstring + descBox.value + "</em></p>\n<hr style=\"border: 1px solid #cfcfcf\">\n" - formatter = links.map((object) => "<h4><a href=\"" + object.url + "\">" + object.headline + "</a></h4>\n"); - tstring = tstring + formatter.join(""); - tstring = tstring + "</div>" - console.log(tstring); - outBox.innerText = tstring; - outBox.style.minHeight = (formatter.length + 9) + "em"; - document.getElementById("preview").innerHTML = tstring; - } + console.log("load"); + function generate() { + console.log("go!"); + var inBox = document.getElementById("in"); + console.log(inBox.value); + var links = JSON.parse(inBox.value); + var outBox = document.getElementById("output"); + var titleBox = document.getElementById("titleIn"); + var descBox = document.getElementById("description"); + var tstring = + "<style>.here,.invmenu a{font-style:italic}.here{font-size:14px;font-weight:400;color:grey}.invmenu{padding:5px 20px;margin:10px 0}</style>\n"; + tstring = + tstring + + "<" + + 'div class="invmenu" style="max-width:100%;background: #f2f2f2;">\n<h3 style="text-align:left;">' + + titleBox.value + + "</h3>\n<p><em>"; + tstring = + tstring + + descBox.value + + '</em></p>\n<hr style="border: 1px solid #cfcfcf">\n'; + formatter = links.map( + (object) => + '<h4><a href="' + + object.url + + '">' + + object.headline + + "</a></h4>\n" + ); + tstring = tstring + formatter.join(""); + tstring = tstring + "</div>"; + console.log(tstring); + outBox.innerText = tstring; + outBox.style.minHeight = formatter.length + 9 + "em"; + document.getElementById("preview").innerHTML = tstring; + } </script> <p></p> - <p>Title of box:</p> <input type="text" id="titleIn" placeholder="Investigating Hope: The Series"> + <p>Title of box:</p> + <input + type="text" + id="titleIn" + placeholder="Investigating Hope: The Series" + /> <p>Description text:</p> - <input type="text" id="description" placeholder="This article is one in a series of investigative pieces about a complaint filed with ASU regarding accusations against on-campus ministry Hope Church."> + <input + type="text" + id="description" + placeholder="This article is one in a series of investigative pieces about a complaint filed with ASU regarding accusations against on-campus ministry Hope Church." + /> <p>Enter the links to generate according to this format:</p> <pre><code class="json">[ { @@ -87,20 +111,37 @@ "url": "yet-another-url" } ]</code></pre> - <p>This format is known as JSON, it's an internet standard that's supposed to be easy for humans and computers to read. - Note how commas are used to separate multiple items but are never used after the last item in a set. This is important, - it will not work if you include a trailing comma where there should not be one.</p> - <textarea name="input" id="in" cols="100" rows="30" placeholder="Please be careful, this will not work if you format the JSON incorrectly"></textarea> - <p><a id="genbutton" href="#output" onclick="generate()">Generate Code</a></p> + <p> + This format is known as JSON, it's an internet standard that's supposed to + be easy for humans and computers to read. Note how commas are used to + separate multiple items but are never used after the last item in a set. + This is important, it will not work if you include a trailing comma where + there should not be one. + </p> + <textarea + name="input" + id="in" + cols="100" + rows="30" + placeholder="Please be careful, this will not work if you format the JSON incorrectly" + ></textarea> + <p> + <a id="genbutton" href="#output" onclick="generate()">Generate Code</a> + </p> <p>Paste the following code into a safeembed</p> <textarea id="output" cols="100" readonly></textarea> - <p><em> Don't forget:</em> For each page you embed on, add the following bit of code just before the <code></h4></code> at the end of the line on the line that corresponds to the current page.</p> + <p> + <em> Don't forget:</em> For each page you embed on, add the following bit + of code just before the <code></h4></code> at the end of the line on + the line that corresponds to the current page. + </p> <pre><code><span class="here">(You are here)</span></code></pre> - - <p>The code generated will look roughly like this:</P> - <div id="preview" style="max-width: 800px;"></div> - <p>Gryphon overrides certain styles by default, so make sure to test on your article.</p> -</body> - -</html> \ No newline at end of file + <p>The code generated will look roughly like this:</p> + <div id="preview" style="max-width: 800px"></div> + <p> + Gryphon overrides certain styles by default, so make sure to test on your + article. + </p> + </body> +</html> diff --git a/tailwind.config.js b/tailwind.config.js index 10bcf23..d33f474 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,34 +1,34 @@ -const defaultTheme = require('tailwindcss/defaultTheme'); +const defaultTheme = require("tailwindcss/defaultTheme"); module.exports = { - purge: ['./src/**/*.{js,jsx,ts,tsx}'], + purge: ["./src/**/*.{js,jsx,ts,tsx}"], // darkMode: 'media', // or 'media' or 'class' theme: { screens: { - 'sm': '640px', - 'md': '768px', - 'lg': '1024px', - 'xl': '1280px', - '2xl': '1536px', - 'portrait': {'raw': '(orientation: portrait)'}, - 'landscape': {'raw': '(orientation: landscape)'}, + sm: "640px", + md: "768px", + lg: "1024px", + xl: "1280px", + "2xl": "1536px", + portrait: { raw: "(orientation: portrait)" }, + landscape: { raw: "(orientation: landscape)" }, }, spacing: { - '0': '0px', - '1': '4px', - '2': '8px', - '3': '12px', - '4': '16px', - '5': '24px', - '6': '32px', - '7': '48px', - '8': '80px', - '9': '800px', + 0: "0px", + 1: "4px", + 2: "8px", + 3: "12px", + 4: "16px", + 5: "24px", + 6: "32px", + 7: "48px", + 8: "80px", + 9: "800px", }, fontFamily: { ...defaultTheme.fontFamily, // serif: ['Didot', 'Didot LT', 'STD', 'Hoefler Text' , 'Garamond', 'Times New Roman', 'serif'] - serif: ['Playfair Display', 'serif'], + serif: ["Playfair Display", "serif"], }, extend: { dropShadow: { @@ -43,7 +43,7 @@ module.exports = { if (opacityVariable !== undefined) { return `rgba(var(--vibrant), var(${opacityVariable}, 1))`; } - return 'rgb(var(--vibrant))'; + return "rgb(var(--vibrant))"; }, light: ({ opacityVariable, opacityValue }) => { if (opacityValue !== undefined) { @@ -52,7 +52,7 @@ module.exports = { if (opacityVariable !== undefined) { return `rgba(var(--light-vibrant), var(${opacityVariable}, 1))`; } - return 'rgb(var(--light-vibrant))'; + return "rgb(var(--light-vibrant))"; }, dark: ({ opacityVariable, opacityValue }) => { if (opacityValue !== undefined) { @@ -61,7 +61,7 @@ module.exports = { if (opacityVariable !== undefined) { return `rgba(var(--dark-vibrant), var(${opacityVariable}, 1))`; } - return 'rgb(var(--dark-vibrant))'; + return "rgb(var(--dark-vibrant))"; }, }, muted: { @@ -72,7 +72,7 @@ module.exports = { if (opacityVariable !== undefined) { return `rgba(var(--muted), var(${opacityVariable}, 1))`; } - return 'rgb(var(--muted))'; + return "rgb(var(--muted))"; }, light: ({ opacityVariable, opacityValue }) => { if (opacityValue !== undefined) { @@ -81,7 +81,7 @@ module.exports = { if (opacityVariable !== undefined) { return `rgba(var(--light-muted), var(${opacityVariable}, 1))`; } - return 'rgb(var(--light-muted))'; + return "rgb(var(--light-muted))"; }, dark: ({ opacityVariable, opacityValue }) => { if (opacityValue !== undefined) { @@ -90,7 +90,7 @@ module.exports = { if (opacityVariable !== undefined) { return `rgba(var(--dark-muted), var(${opacityVariable}, 1))`; } - return 'rgb(var(--dark-muted))'; + return "rgb(var(--dark-muted))"; }, }, }, diff --git a/yarn.lock b/yarn.lock index 68bad93..bcaaa47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11144,7 +11144,7 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= -prettier@^2.0.5: +prettier@2.3.2, prettier@^2.0.5: version "2.3.2" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==