run prettier

This commit is contained in:
Chuck Dries 2021-07-12 18:54:08 -07:00
parent 5df4c2baf4
commit d8655904fa
31 changed files with 1183 additions and 917 deletions

View File

@ -2,24 +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,
'no-unused-vars': 1,
'react/jsx-sort-props': 1,
rules: {
"react/prop-types": 0,
"no-unused-vars": 1,
"react/jsx-sort-props": 1,
},
};

View File

@ -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 }}

139
.vscode/launch.json vendored
View File

@ -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
}
]
}
{
"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
}
]
}

View File

@ -1,3 +1,3 @@
{
"python.linting.pylintEnabled": false
}
"python.linting.pylintEnabled": false
}

32
.vscode/tasks.json vendored
View File

@ -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"
}
]
}
{
// 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"
}
]
}

View File

@ -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)
- [ ] static files (resume)

View File

@ -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';

View File

@ -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",
],
};

View File

@ -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,

View File

@ -1 +1 @@
import './src/styles/global.css';
import "./src/styles/global.css";

View File

@ -1,7 +1,7 @@
module.exports = {
plugins: {
tailwindcss: {},
'postcss-nested': {},
"postcss-nested": {},
autoprefixer: {},
},
};

View File

@ -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;
export default themeBreakpoints;

View File

@ -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">&#11104;</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">&#11106;</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">&#11104;</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">&#11106;</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;

View File

@ -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;
export default MetadataItem;

View File

@ -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>
);
>
{children}
</a>
);

View File

@ -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;
};

View File

@ -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>
);
};

View File

@ -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
}
`;
`;

View File

@ -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>
);

View File

@ -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 couldnt 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>.

View File

@ -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!

View File

@ -1,47 +1,69 @@
import * as React from 'react';
import { Link, graphql } from 'gatsby';
import { GatsbyImage, getImage } from 'gatsby-plugin-image';
import { Helmet } from 'react-helmet';
import { take } from 'ramda';
import classnames from 'classnames';
import posthog from 'posthog-js';
import * as React from "react";
import { Link, graphql } from "gatsby";
import { GatsbyImage, getImage } from "gatsby-plugin-image";
import { Helmet } from "react-helmet";
import { take } from "ramda";
import classnames from "classnames";
import posthog from "posthog-js";
import { getVibrantToHelmetSafeBodyStyle, getVibrant, getAspectRatio } from '../utils';
import { HeroA } from '../components/Index/HeroLink';
import {
getVibrantToHelmetSafeBodyStyle,
getVibrant,
getAspectRatio,
} from "../utils";
import { HeroA } from "../components/Index/HeroLink";
const env = process.env.GATSBY_ACTIVE_ENV || process.env.NODE_ENV || 'development';
const env =
process.env.GATSBY_ACTIVE_ENV || process.env.NODE_ENV || "development";
const getDifferentRand = (range, lastNs, iterations = 0) => {
const n = Math.floor(Math.random() * range);
if (lastNs.findIndex(x => x === n) > -1 && iterations < 5) {
console.log('got dupe, trying again', n);
if (lastNs.findIndex((x) => x === n) > -1 && iterations < 5) {
console.log("got dupe, trying again", n);
return getDifferentRand(range, lastNs, iterations + 1);
}
return n;
};
const IndexPage = ({ data: { allFile: { edges } } }) => {
const IndexPage = ({
data: {
allFile: { edges },
},
}) => {
const [isClient, setIsClient] = React.useState(false);
const [imageIndex, setImageIndex] = React.useState(0);
const images = React.useMemo(() => edges.map((edge) => edge.node), [edges]);
const image = React.useMemo(() => {
console.log('ii', imageIndex);
console.log("ii", imageIndex);
return images[imageIndex];
}, [images, imageIndex]);
const shuffleImage = React.useCallback((currentImage) => {
const lastThreeImages = JSON.parse(localStorage.getItem('lastHeros')) || [];
if (env === 'production') {
try {
// eslint-disable-next-line
posthog.capture('[shuffle image]', { currentImage: currentImage?.base });
window.plausible('Shuffle', {props: { currentImage: currentImage?.base }});
} catch (e) {/* do nothing */}
}
const index = getDifferentRand(images.length, lastThreeImages);
localStorage.setItem('lastHeros', JSON.stringify(take(3, [index, ...lastThreeImages])));
setImageIndex(index);
}, [images.length]);
const shuffleImage = React.useCallback(
(currentImage) => {
const lastThreeImages =
JSON.parse(localStorage.getItem("lastHeros")) || [];
if (env === "production") {
try {
// eslint-disable-next-line
posthog.capture("[shuffle image]", {
currentImage: currentImage?.base,
});
window.plausible("Shuffle", {
props: { currentImage: currentImage?.base },
});
} catch (e) {
/* do nothing */
}
}
const index = getDifferentRand(images.length, lastThreeImages);
localStorage.setItem(
"lastHeros",
JSON.stringify(take(3, [index, ...lastThreeImages]))
);
setImageIndex(index);
},
[images.length]
);
// pick random image on page hydration
React.useEffect(() => {
@ -54,165 +76,257 @@ const IndexPage = ({ data: { allFile: { edges } } }) => {
React.useEffect(() => {
const keyListener = (e) => {
switch (e.code) {
case 'ArrowRight': {
if (imageIndex === images.length - 1) {
setImageIndex(0);
case "ArrowRight": {
if (imageIndex === images.length - 1) {
setImageIndex(0);
return;
}
setImageIndex(imageIndex + 1);
return;
}
setImageIndex(imageIndex + 1);
return;
}
case 'ArrowLeft': {
if (imageIndex === 0) {
setImageIndex(images.length - 1);
case "ArrowLeft": {
if (imageIndex === 0) {
setImageIndex(images.length - 1);
return;
}
setImageIndex(imageIndex - 1);
return;
}
setImageIndex(imageIndex - 1);
return;
}
}
};
document.addEventListener('keydown', keyListener);
document.addEventListener("keydown", keyListener);
return () => {
document.removeEventListener('keydown', keyListener);
document.removeEventListener("keydown", keyListener);
};
}, [imageIndex, images.length]);
const vibrant = getVibrant(image);
const ar = getAspectRatio(image);
return (<>
<Helmet>
<title>Chuck Dries</title>
<body
className={classnames(isClient ? 'bg-vibrant-dark' : '')}
style={getVibrantToHelmetSafeBodyStyle(vibrant)}
/>
</Helmet>
{/* WIP: ipad portrait hits md breakpoint, looks bad */}
<main
className={classnames('font-serif hero', ar > 1 || !isClient
? 'landscape:grid portrait:flex portrait:flex-col' : 'portrait:grid landscape:flex landscape:flex-row-reverse')}
>
{isClient ?
<GatsbyImage
alt=""
return (
<>
<Helmet>
<title>Chuck Dries</title>
<body
className={classnames(isClient ? "bg-vibrant-dark" : "")}
style={getVibrantToHelmetSafeBodyStyle(vibrant)}
/>
</Helmet>
{/* WIP: ipad portrait hits md breakpoint, looks bad */}
<main
className={classnames(
"font-serif hero",
ar > 1 || !isClient
? "landscape:grid portrait:flex portrait:flex-col"
: "portrait:grid landscape:flex landscape:flex-row-reverse"
)}
>
{isClient ? (
<GatsbyImage
alt=""
className={classnames(
ar > 1 || !isClient
? "landscape:h-screen portrait:h-two-thirds-vw"
: "h-screen portrait:w-full landscape:w-1/2"
)}
image={getImage(image)}
loading="eager"
style={{
gridArea: "1/1",
}}
/>
) : (
// 67vw = 1/1.49253731 = 1/aspect ratio of my camera lol
<div
className="landscape:h-screen portrait:h-two-thirds-vw w-full"
style={{ gridArea: "1/1" }}
></div>
)}
<div
className={classnames(
ar > 1 || !isClient ? 'landscape:h-screen portrait:h-two-thirds-vw' : 'h-screen portrait:w-full landscape:w-1/2',
"relative grid",
ar <= 1
? "place-items-end landscape:place-items-center"
: "place-items-end"
)}
image={getImage(image)}
loading="eager"
style={{
gridArea: '1/1',
}} />
// 67vw = 1/1.49253731 = 1/aspect ratio of my camera lol
: <div className="landscape:h-screen portrait:h-two-thirds-vw w-full" style={{gridArea: '1/1' }}></div> }
<div className={classnames('relative grid', ar <= 1 ? 'place-items-end landscape:place-items-center' : 'place-items-end')} style={{gridArea: '1/1'}}>
<div className="">
<div className="flex mx-6 justify-end">
<div className="flex my-2 items-center flex-col">
style={{ gridArea: "1/1" }}
>
<div className="">
<div className="flex mx-6 justify-end">
<div className="flex my-2 items-center flex-col">
<Link
className={classnames(
"hover:underline inline-block px-1 my-1 mr-2 text-md rounded-md border-2",
isClient &&
"text-muted-dark bg-muted-light hover:border-muted border-muted-dark"
)}
// style={{top: '5px'}}
id="image-link"
title="view image details"
to={`/photogallery/${image.base}/`}
>
<span className="icon-offset">
<ion-icon name="image"></ion-icon>
</span>
</Link>
<button
className={classnames(
"hover:underline inline-block px-1 my-1 mr-2 text-md rounded-md border-2",
isClient &&
"text-muted-dark bg-muted-light hover:border-muted border-muted-dark"
)}
id="shuffle-button"
onClick={() => {
shuffleImage(image);
}}
title="shuffle image"
type="button"
>
<span className="icon-offset">
<ion-icon name="shuffle"></ion-icon>
</span>
</button>
</div>
<Link
className={classnames(
'hover:underline inline-block px-1 my-1 mr-2 text-md rounded-md border-2',
isClient && 'text-muted-dark bg-muted-light hover:border-muted border-muted-dark')}
// style={{top: '5px'}}
id="image-link"
title="view image details"
to={`/photogallery/${image.base}/`}
"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 hover:border-muted border-muted-dark"
)}
id="photogallery-link"
to="/photogallery/"
>
<span className="icon-offset"><ion-icon name="image"></ion-icon></span>
Photography Gallery
</Link>
<button
className={classnames(
'hover:underline inline-block px-1 my-1 mr-2 text-md rounded-md border-2',
isClient && 'text-muted-dark bg-muted-light hover:border-muted border-muted-dark')}
id="shuffle-button"
onClick={() => {
shuffleImage(image);
}}
title="shuffle image"
type="button"
>
<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 hover:border-muted border-muted-dark')}
id="photogallery-link"
to="/photogallery/"
ar > 1 && "landscape:shadow-lg",
"md:px-6 px-4 md:py-5 py-3 rounded-l-md mb-4",
isClient &&
"bg-vibrant-dark bg-opacity-60 backdrop-filter backdrop-blur-xl"
)}
>
Photography Gallery
</Link>
</div>
<section
className={classnames(
ar > 1 && 'landscape:shadow-lg',
'md:px-6 px-4 md:py-5 py-3 rounded-l-md mb-4', isClient &&
'bg-vibrant-dark bg-opacity-60 backdrop-filter backdrop-blur-xl'
)}
>
<div
className={classnames('mx-auto filter drop-shadow items-end', ar > 1 || !isClient ? 'landscape:flex' : 'portrait:flex')}
>
<div className="mr-5 flex-auto">
<h1 className={classnames('font-black text-4xl sm:text-5xl md:text-6xl', isClient && 'text-vibrant-light')}>Chuck Dries</h1>
<h2 className={classnames('text-xl md:text-2xl', isClient && 'text-vibrant')}>Full Stack Software Engineer &amp; Hobbyist Photographer</h2>
<div
className={classnames(
"mx-auto filter drop-shadow items-end",
ar > 1 || !isClient ? "landscape:flex" : "portrait:flex"
)}
>
<div className="mr-5 flex-auto">
<h1
className={classnames(
"font-black text-4xl sm:text-5xl md:text-6xl",
isClient && "text-vibrant-light"
)}
>
Chuck Dries
</h1>
<h2
className={classnames(
"text-xl md:text-2xl",
isClient && "text-vibrant"
)}
>
Full Stack Software Engineer &amp; Hobbyist Photographer
</h2>
</div>
{/* {<div className="border-t-2 border-muted-light mt-2 mr-2 mb-1" style={{width: 30}}></div>} */}
<ul
className={
("md:mr-4", classnames(isClient && "text-muted-light"))
}
>
<li>Software Engineer, Axosoft</li>
<li>
<HeroA
className="ml-0"
href="mailto:chuck@chuckdries.com"
isClient={isClient}
>
chuck@chuckdries.com
</HeroA>
/<span className="ml-2">602.618.0414</span>
</li>
<li>
<HeroA
className="ml-0"
href="http://github.com/chuckdries"
isClient={isClient}
>
Github
</HeroA>
/
<HeroA
href="https://www.linkedin.com/in/chuckdries/"
isClient={isClient}
>
LinkedIn
</HeroA>
/
<HeroA
href="https://devpost.com/chuckdries"
isClient={isClient}
>
Devpost
</HeroA>
/
<HeroA
href="/CharlesDriesResumeCurrent.pdf"
isClient={isClient}
>
Resume [pdf]
</HeroA>
/
<HeroA
href="https://medium.com/@chuckdries"
isClient={isClient}
>
Medium (blog)
</HeroA>
</li>
</ul>
</div>
{/* {<div className="border-t-2 border-muted-light mt-2 mr-2 mb-1" style={{width: 30}}></div>} */}
<ul className={'md:mr-4', classnames(isClient && 'text-muted-light')}>
<li>Software Engineer, Axosoft</li>
<li><HeroA className="ml-0" href="mailto:chuck@chuckdries.com" isClient={isClient}>chuck@chuckdries.com</HeroA>/<span className="ml-2">602.618.0414</span></li>
<li>
<HeroA className="ml-0" href="http://github.com/chuckdries" isClient={isClient}>Github</HeroA>/
<HeroA href="https://www.linkedin.com/in/chuckdries/" isClient={isClient}>LinkedIn</HeroA>/
<HeroA href="https://devpost.com/chuckdries" isClient={isClient}>Devpost</HeroA>/
<HeroA href="/CharlesDriesResumeCurrent.pdf" isClient={isClient}>Resume [pdf]</HeroA>/
<HeroA href="https://medium.com/@chuckdries" isClient={isClient}>Medium (blog)</HeroA>
</li>
</ul>
</div>
</section>
</section>
</div>
</div>
</div>
</main>
</>);
</main>
</>
);
};
export const query = graphql`
{
allFile(
filter: { sourceInstanceName: {eq: "gallery"} }
sort: {order: DESC, fields: fields___imageMeta___dateTaken}
) {
edges {
node {
relativePath
base
childImageSharp {
fluid {
aspectRatio
{
allFile(
filter: { sourceInstanceName: { eq: "gallery" } }
sort: { order: DESC, fields: fields___imageMeta___dateTaken }
) {
edges {
node {
relativePath
base
childImageSharp {
fluid {
aspectRatio
}
gatsbyImageData(
layout: FULL_WIDTH
placeholder: NONE
breakpoints: [750, 1080, 1366, 1920, 2560]
)
}
gatsbyImageData(
layout: FULL_WIDTH
placeholder: NONE
breakpoints: [750, 1080, 1366, 1920, 2560]
)
}
fields {
imageMeta {
vibrant {
...VibrantColors
fields {
imageMeta {
vibrant {
...VibrantColors
}
}
}
}
}
}
}
}
`;
export default IndexPage;

View File

@ -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;

View File

@ -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");
}
@variants responsive {
.h-two-thirds-vw {
@ -63,7 +63,7 @@ a {
margin-left: 3px;
transform: translate(0px);
display: inline-block;
transition: all .2s;
transition: all 0.2s;
}
.arrow-left-before:before {

View File

@ -3,4 +3,3 @@
@apply text-3xl font-bold;
}
}

View File

@ -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}`;

View File

@ -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">

View File

@ -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>

View File

@ -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>
<!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>

View File

@ -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>&lt;/h4&gt;</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>&lt;/h4&gt;</code> at the end of the line on
the line that corresponds to the current page.
</p>
<pre><code>&lt;span class="here"&gt;(You are here)&lt;/span&gt;</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>
<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>

View File

@ -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: {
colors: {
@ -40,7 +40,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) {
@ -49,7 +49,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) {
@ -58,7 +58,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: {
@ -69,7 +69,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) {
@ -78,7 +78,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) {
@ -87,7 +87,7 @@ module.exports = {
if (opacityVariable !== undefined) {
return `rgba(var(--dark-muted), var(${opacityVariable}, 1))`;
}
return 'rgb(var(--dark-muted))';
return "rgb(var(--dark-muted))";
},
},
},