Run Prettier across projects
Problem: Prettier was not running when I saved Emacs buffers. Why? - prettier-js-mode needs needs node; lorri exposes node to direnv; direnv exposes node to Emacs; lorri was not working as expected. Solution: Now that I'm using nix-buffer, I can properly expose node (and other dependencies) to my Emacs buffers. Now Prettier is working. Commentary: Since prettier hadn't worked for so long, I stopped thinking about it. As such, I did not include it as a dependency in boilerplate/typescript. I added it now. I retroactively ran prettier across a few of my frontend projects to unify the code styling. I may need to run... ```shell $ cd ~/briefcase $ nix-shell $ npx prettier --list-different "**/*.{js,ts,jsx,tsx,html,css,json}" ``` ...to see which files I should have formatted.
This commit is contained in:
parent
f4f7f454fa
commit
514136c99a
22 changed files with 181 additions and 128 deletions
|
@ -4,11 +4,13 @@
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "npx parcel src/index.html & npx tsc --watch --noEmit"
|
"dev": "parcel src/index.html & npx tsc --watch --noEmit",
|
||||||
|
"prettier": "prettier --ignore-path .gitignore --write \"**/*.{js,ts,jsx,tsx,html,css.json}\""
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^13.9.3",
|
"@types/node": "^13.9.3",
|
||||||
"parcel-bundler": "^1.12.4",
|
"parcel-bundler": "^1.12.4",
|
||||||
|
"prettier": "^2.0.2",
|
||||||
"tailwindcss": "^1.2.0",
|
"tailwindcss": "^1.2.0",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<link rel="stylesheet" href="./index.css">
|
<link rel="stylesheet" href="./index.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="mount"></div>
|
<div id="mount"></div>
|
||||||
|
|
|
@ -4287,6 +4287,11 @@ prelude-ls@~1.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
||||||
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
|
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
|
||||||
|
|
||||||
|
prettier@^2.0.2:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.2.tgz#1ba8f3eb92231e769b7fcd7cb73ae1b6b74ade08"
|
||||||
|
integrity sha512-5xJQIPT8BraI7ZnaDwSbu5zLrB6vvi8hVV58yHQ+QK64qrY40dULy0HSRlQ2/2IdzeBpjhDkqdcFBnFeDEMVdg==
|
||||||
|
|
||||||
pretty-hrtime@^1.0.3:
|
pretty-hrtime@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
|
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
|
||||||
|
|
6
scratch/deepmind/part_two/package-lock.json
generated
6
scratch/deepmind/part_two/package-lock.json
generated
|
@ -28,6 +28,12 @@
|
||||||
"integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
|
"integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"prettier": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-5xJQIPT8BraI7ZnaDwSbu5zLrB6vvi8hVV58yHQ+QK64qrY40dULy0HSRlQ2/2IdzeBpjhDkqdcFBnFeDEMVdg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"author": "William Carroll",
|
"author": "William Carroll",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"prettier": "^2.0.2",
|
||||||
"ts-node": "^8.6.2",
|
"ts-node": "^8.6.2",
|
||||||
"typescript": "^3.7.5"
|
"typescript": "^3.7.5"
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ function sortScores(xs: Array<number>, highest: number): Array<number> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < xs.length; i += 1) {
|
for (let i = 0; i < xs.length; i += 1) {
|
||||||
counts[xs[i]] += 1
|
counts[xs[i]] += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = highest; i >= 0; i -= 1) {
|
for (let i = highest; i >= 0; i -= 1) {
|
||||||
|
@ -22,29 +22,28 @@ function sortScores(xs: Array<number>, highest: number): Array<number> {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Tests
|
// Tests
|
||||||
let desc = 'no scores';
|
let desc = "no scores";
|
||||||
let actual = sortScores([], 100);
|
let actual = sortScores([], 100);
|
||||||
let expected = [];
|
let expected = [];
|
||||||
assertEqual(JSON.stringify(actual), JSON.stringify(expected), desc);
|
assertEqual(JSON.stringify(actual), JSON.stringify(expected), desc);
|
||||||
|
|
||||||
desc = 'one score';
|
desc = "one score";
|
||||||
actual = sortScores([55], 100);
|
actual = sortScores([55], 100);
|
||||||
expected = [55];
|
expected = [55];
|
||||||
assertEqual(JSON.stringify(actual), JSON.stringify(expected), desc);
|
assertEqual(JSON.stringify(actual), JSON.stringify(expected), desc);
|
||||||
|
|
||||||
desc = 'two scores';
|
desc = "two scores";
|
||||||
actual = sortScores([30, 60], 100);
|
actual = sortScores([30, 60], 100);
|
||||||
expected = [60, 30];
|
expected = [60, 30];
|
||||||
assertEqual(JSON.stringify(actual), JSON.stringify(expected), desc);
|
assertEqual(JSON.stringify(actual), JSON.stringify(expected), desc);
|
||||||
|
|
||||||
desc = 'many scores';
|
desc = "many scores";
|
||||||
actual = sortScores([37, 89, 41, 65, 91, 53], 100);
|
actual = sortScores([37, 89, 41, 65, 91, 53], 100);
|
||||||
expected = [91, 89, 65, 53, 41, 37];
|
expected = [91, 89, 65, 53, 41, 37];
|
||||||
assertEqual(JSON.stringify(actual), JSON.stringify(expected), desc);
|
assertEqual(JSON.stringify(actual), JSON.stringify(expected), desc);
|
||||||
|
|
||||||
desc = 'repeated scores';
|
desc = "repeated scores";
|
||||||
actual = sortScores([20, 10, 30, 30, 10, 20], 100);
|
actual = sortScores([20, 10, 30, 30, 10, 20], 100);
|
||||||
expected = [30, 30, 20, 20, 10, 10];
|
expected = [30, 30, 20, 20, 10, 10];
|
||||||
assertEqual(JSON.stringify(actual), JSON.stringify(expected), desc);
|
assertEqual(JSON.stringify(actual), JSON.stringify(expected), desc);
|
||||||
|
|
|
@ -4,11 +4,13 @@
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "npx parcel src/index.html & npx tsc --watch --noEmit"
|
"dev": "parcel src/index.html & npx tsc --watch --noEmit",
|
||||||
|
"prettier": "prettier --ignore-path .gitignore --write \"**/*.{js,ts,jsx,tsx,html,css.json}\""
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^13.9.3",
|
"@types/node": "^13.9.3",
|
||||||
"parcel-bundler": "^1.12.4",
|
"parcel-bundler": "^1.12.4",
|
||||||
|
"prettier": "^2.0.2",
|
||||||
"tailwindcss": "^1.2.0",
|
"tailwindcss": "^1.2.0",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
const tailwindcss = require('tailwindcss')
|
const tailwindcss = require("tailwindcss");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [tailwindcss("./tailwind.config.js")],
|
||||||
tailwindcss('./tailwind.config.js')
|
};
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,74 +1,84 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
function ProgressBar(props: {
|
function ProgressBar(props: {
|
||||||
done: number,
|
done: number;
|
||||||
total: number,
|
total: number;
|
||||||
units: string,
|
units: string;
|
||||||
color: string,
|
color: string;
|
||||||
}) {
|
}) {
|
||||||
const { done, total, units, color } = props
|
const { done, total, units, color } = props;
|
||||||
const width = Math.floor(done / total * 100)
|
const width = Math.floor((done / total) * 100);
|
||||||
const rest = 100 - width
|
const rest = 100 - width;
|
||||||
|
|
||||||
let [fg, bg] = [`bg-${color}-600`, `bg-${color}-100`]
|
let [fg, bg] = [`bg-${color}-600`, `bg-${color}-100`];
|
||||||
|
|
||||||
if (color === 'white') {
|
if (color === "white") {
|
||||||
[fg, bg] = ['bg-gray-600', 'bg-gray-100']
|
[fg, bg] = ["bg-gray-600", "bg-gray-100"];
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`relative ${bg} h-5`}>
|
<div className={`relative ${bg} h-5`}>
|
||||||
<div className={`${fg} h-5 absolute top-0 left-0`} style={{width: `${width}%`}}></div>
|
<div
|
||||||
<p className="absolute text-xs pl-1 pt-1">{done} of {total} {units}</p>
|
className={`${fg} h-5 absolute top-0 left-0`}
|
||||||
|
style={{ width: `${width}%` }}
|
||||||
|
></div>
|
||||||
|
<p className="absolute text-xs pl-1 pt-1">
|
||||||
|
{done} of {total} {units}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Goal(props: {
|
function Goal(props: {
|
||||||
subject: string,
|
subject: string;
|
||||||
goal: string,
|
goal: string;
|
||||||
done: number,
|
done: number;
|
||||||
total: number,
|
total: number;
|
||||||
units: string,
|
units: string;
|
||||||
color: string,
|
color: string;
|
||||||
}) {
|
}) {
|
||||||
const { subject, goal, done, total, units, color } = props
|
const { subject, goal, done, total, units, color } = props;
|
||||||
const width = "6em"
|
const width = "6em";
|
||||||
|
|
||||||
const Tr = (props: {
|
const Tr = (props: {
|
||||||
label: string,
|
label: string;
|
||||||
value: string,
|
value: string;
|
||||||
valueComponent?: React.ReactElement,
|
valueComponent?: React.ReactElement;
|
||||||
}) => (
|
}) => (
|
||||||
<tr className="flex py-2">
|
<tr className="flex py-2">
|
||||||
<td className="text-gray-600" style={{width: width}}>{props.label}</td>
|
<td className="text-gray-600" style={{ width: width }}>
|
||||||
|
{props.label}
|
||||||
|
</td>
|
||||||
<td className="flex-1">
|
<td className="flex-1">
|
||||||
{props.valueComponent ? props.valueComponent : props.value}
|
{props.valueComponent ? props.valueComponent : props.value}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table className="w-full mb-10">
|
<table className="w-full mb-10">
|
||||||
<tbody>
|
<tbody>
|
||||||
<Tr label="Subject" value={subject} />
|
<Tr label="Subject" value={subject} />
|
||||||
<Tr label="Goal" value={goal} />
|
<Tr label="Goal" value={goal} />
|
||||||
<Tr label="Progress" value={goal} valueComponent={
|
<Tr
|
||||||
<ProgressBar done={done} total={total} units={units} color={color} />
|
label="Progress"
|
||||||
}/>
|
value={goal}
|
||||||
|
valueComponent={
|
||||||
|
<ProgressBar
|
||||||
|
done={done}
|
||||||
|
total={total}
|
||||||
|
units={units}
|
||||||
|
color={color}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Copy(props: {
|
function Copy(props: { children: React.ReactNode }) {
|
||||||
children: React.ReactNode
|
return <p className="pb-4 leading-loose">{props.children}</p>;
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<p className="pb-4 leading-loose">
|
|
||||||
{props.children}
|
|
||||||
</p>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
@ -78,7 +88,7 @@ function App() {
|
||||||
<h1 className="text-center pt-12 pb-6">Goals</h1>
|
<h1 className="text-center pt-12 pb-6">Goals</h1>
|
||||||
<Copy>
|
<Copy>
|
||||||
For me, a goal is something that is difficult for me to complete but
|
For me, a goal is something that is difficult for me to complete but
|
||||||
easy for me to measure. I tend to add new goals as time progresses,
|
easy for me to measure. I tend to add new goals as time progresses,
|
||||||
mistakenly assuming that I can support additional goals for free. To
|
mistakenly assuming that I can support additional goals for free. To
|
||||||
counterbalance my tendancy to casually accumulate goals, I aim to only
|
counterbalance my tendancy to casually accumulate goals, I aim to only
|
||||||
have three goals; I will not add a new goal until I complete an
|
have three goals; I will not add a new goal until I complete an
|
||||||
|
@ -90,27 +100,33 @@ function App() {
|
||||||
</Copy>
|
</Copy>
|
||||||
</section>
|
</section>
|
||||||
<section className="pt-4">
|
<section className="pt-4">
|
||||||
<Goal subject="Meditation"
|
<Goal
|
||||||
goal="Meditate for 10,000 hours"
|
subject="Meditation"
|
||||||
done={100}
|
goal="Meditate for 10,000 hours"
|
||||||
total={10000}
|
done={100}
|
||||||
units="hrs"
|
total={10000}
|
||||||
color="purple" />
|
units="hrs"
|
||||||
<Goal subject="Debt"
|
color="purple"
|
||||||
goal="Pay my student debt balance"
|
/>
|
||||||
done={30000}
|
<Goal
|
||||||
total={70000}
|
subject="Debt"
|
||||||
units="USD"
|
goal="Pay my student debt balance"
|
||||||
color="green" />
|
done={30000}
|
||||||
<Goal subject="Brazilian Jiu Jitsu"
|
total={70000}
|
||||||
goal="Train until an instructor gives me a black belt"
|
units="USD"
|
||||||
done={1}
|
color="green"
|
||||||
total={5}
|
/>
|
||||||
units="belts"
|
<Goal
|
||||||
color="white" />
|
subject="Brazilian Jiu Jitsu"
|
||||||
|
goal="Train until an instructor gives me a black belt"
|
||||||
|
done={1}
|
||||||
|
total={5}
|
||||||
|
units="belts"
|
||||||
|
color="white"
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<link rel="stylesheet" href="./index.css">
|
<link rel="stylesheet" href="./index.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="mount"></div>
|
<div id="mount"></div>
|
||||||
|
|
|
@ -4,4 +4,4 @@ module.exports = {
|
||||||
},
|
},
|
||||||
variants: {},
|
variants: {},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
@ -19,7 +15,5 @@
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react"
|
"jsx": "react"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src/**/*"]
|
||||||
"src/**/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4287,6 +4287,11 @@ prelude-ls@~1.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
||||||
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
|
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
|
||||||
|
|
||||||
|
prettier@^2.0.2:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.2.tgz#1ba8f3eb92231e769b7fcd7cb73ae1b6b74ade08"
|
||||||
|
integrity sha512-5xJQIPT8BraI7ZnaDwSbu5zLrB6vvi8hVV58yHQ+QK64qrY40dULy0HSRlQ2/2IdzeBpjhDkqdcFBnFeDEMVdg==
|
||||||
|
|
||||||
pretty-hrtime@^1.0.3:
|
pretty-hrtime@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
|
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
|
||||||
|
|
|
@ -4,7 +4,10 @@
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="description" content="Learn to code" />
|
<meta name="description" content="Learn to code" />
|
||||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
|
<link
|
||||||
|
href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
<title>Learn to code</title>
|
<title>Learn to code</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="font-serif container max-w-2xl mx-auto px-8">
|
<body class="font-serif container max-w-2xl mx-auto px-8">
|
||||||
|
@ -42,33 +45,58 @@
|
||||||
<h2 class="text-3xl">Pricing</h2>
|
<h2 class="text-3xl">Pricing</h2>
|
||||||
<p class="leading-relaxed mb-4">
|
<p class="leading-relaxed mb-4">
|
||||||
I charge <bold class="font-bold">£50</bold> per hour for video lessons
|
I charge <bold class="font-bold">£50</bold> per hour for video lessons
|
||||||
and <bold class="font-bold">£100</bold> per hour for in-person
|
and <bold class="font-bold">£100</bold> per hour for in-person sessions.
|
||||||
sessions. I am currently based in South Kensington, London.
|
I am currently based in South Kensington, London.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="my-4">
|
<div class="my-4">
|
||||||
<h2 class="text-3xl">Contact</h2>
|
<h2 class="text-3xl">Contact</h2>
|
||||||
<p class="leading-relaxed mb-4">
|
<p class="leading-relaxed mb-4">
|
||||||
Whether you want to sign-up or simply want to learn more, send me an
|
Whether you want to sign-up or simply want to learn more, send me an
|
||||||
email at <a href="mailto:wpcarro@gmail.com" class="font-bold text-blue-600 hover:underline">wpcarro@gmail.com</a>.
|
email at
|
||||||
|
<a
|
||||||
|
href="mailto:wpcarro@gmail.com"
|
||||||
|
class="font-bold text-blue-600 hover:underline"
|
||||||
|
>wpcarro@gmail.com</a
|
||||||
|
>.
|
||||||
</p>
|
</p>
|
||||||
<p class="text-center my-8">Why delay? <em>Start today.</em></p>
|
<p class="text-center my-8">Why delay? <em>Start today.</em></p>
|
||||||
</div>
|
</div>
|
||||||
<footer class="mb-8 lg:flex">
|
<footer class="mb-8 lg:flex">
|
||||||
<a class="block py-2 lg:w-1/4 text-center hover:underline" href="https://blog.wpcarro.dev">Blog</a>
|
<a
|
||||||
<a class="block py-2 lg:w-1/4 text-center hover:underline" href="https://linkedin.com/in/williampatrickcarroll">LinkedIn</a>
|
class="block py-2 lg:w-1/4 text-center hover:underline"
|
||||||
<a class="block py-2 lg:w-1/4 text-center hover:underline" href="https://twitter.com/wpcarro">Twitter</a>
|
href="https://blog.wpcarro.dev"
|
||||||
<a class="block py-2 lg:w-1/4 text-center hover:underline" href="https://github.com/wpcarro">Github</a>
|
>Blog</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
class="block py-2 lg:w-1/4 text-center hover:underline"
|
||||||
|
href="https://linkedin.com/in/williampatrickcarroll"
|
||||||
|
>LinkedIn</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
class="block py-2 lg:w-1/4 text-center hover:underline"
|
||||||
|
href="https://twitter.com/wpcarro"
|
||||||
|
>Twitter</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
class="block py-2 lg:w-1/4 text-center hover:underline"
|
||||||
|
href="https://github.com/wpcarro"
|
||||||
|
>Github</a
|
||||||
|
>
|
||||||
</footer>
|
</footer>
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-160226702-1">
|
<script
|
||||||
</script>
|
async
|
||||||
|
src="https://www.googletagmanager.com/gtag/js?id=UA-160226702-1"
|
||||||
|
></script>
|
||||||
<script>
|
<script>
|
||||||
window.dataLayer = window.dataLayer || [];
|
window.dataLayer = window.dataLayer || [];
|
||||||
function gtag(){dataLayer.push(arguments);}
|
function gtag() {
|
||||||
gtag('js', new Date());
|
dataLayer.push(arguments);
|
||||||
|
}
|
||||||
|
gtag("js", new Date());
|
||||||
|
|
||||||
gtag('config', 'UA-160226702-1');
|
gtag("config", "UA-160226702-1");
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
const tailwindcss = require('tailwindcss')
|
const tailwindcss = require("tailwindcss");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [tailwindcss("./tailwind.config.js")],
|
||||||
tailwindcss('./tailwind.config.js')
|
};
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import type { Book } from "./store";
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { isLoading, books } = useTypedSelector(state => ({
|
const { isLoading, books } = useTypedSelector((state) => ({
|
||||||
isLoading: state.isLoading,
|
isLoading: state.isLoading,
|
||||||
books: state.books,
|
books: state.books,
|
||||||
}));
|
}));
|
||||||
|
@ -16,7 +16,7 @@ const App: React.FC = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
const entries = await getClient().getEntries();
|
const entries = await getClient().getEntries();
|
||||||
const books = entries.items.map(x => x.fields) as Book[];
|
const books = entries.items.map((x) => x.fields) as Book[];
|
||||||
|
|
||||||
dispatch(actions.setBooks(books));
|
dispatch(actions.setBooks(books));
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,12 @@ const App: React.FC = () => {
|
||||||
<div className="container mx-auto">
|
<div className="container mx-auto">
|
||||||
<h1 className="py-6 text-2xl">Books</h1>
|
<h1 className="py-6 text-2xl">Books</h1>
|
||||||
<ul>
|
<ul>
|
||||||
{books.map(book => (
|
{books.map((book) => (
|
||||||
<li key={book.title} className="py-3">
|
<li key={book.title} className="py-3">
|
||||||
<p><span className="font-bold pr-3">{book.title}</span><span className="text-gray-600">{book.author}</span></p>
|
<p>
|
||||||
|
<span className="font-bold pr-3">{book.title}</span>
|
||||||
|
<span className="text-gray-600">{book.author}</span>
|
||||||
|
</p>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -8,10 +8,10 @@ let client: ContentfulClientApi;
|
||||||
|
|
||||||
// Idempotent way to get a reference to the Contentful client.
|
// Idempotent way to get a reference to the Contentful client.
|
||||||
export const getClient = (): ContentfulClientApi => {
|
export const getClient = (): ContentfulClientApi => {
|
||||||
if (typeof client !== 'undefined') {
|
if (typeof client !== "undefined") {
|
||||||
return client;
|
return client;
|
||||||
} else {
|
} else {
|
||||||
if (typeof space === 'string' && typeof accessToken === 'string') {
|
if (typeof space === "string" && typeof accessToken === "string") {
|
||||||
let client = createClient({
|
let client = createClient({
|
||||||
space,
|
space,
|
||||||
accessToken,
|
accessToken,
|
||||||
|
@ -19,7 +19,9 @@ export const getClient = (): ContentfulClientApi => {
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Please set CONTENTFUL_SPACE_ID and CONTENTFUL_ACCESS_TOKEN');
|
throw new Error(
|
||||||
|
"Please set CONTENTFUL_SPACE_ID and CONTENTFUL_ACCESS_TOKEN"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<link rel="stylesheet" href="./index.css">
|
<link rel="stylesheet" href="./index.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="mount"></div>
|
<div id="mount"></div>
|
||||||
|
|
|
@ -22,9 +22,9 @@ export const { actions, reducer } = createSlice({
|
||||||
name: "application",
|
name: "application",
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
toggleIsLoading: state => ({ ...state, isLoading: !state.isLoading }),
|
toggleIsLoading: (state) => ({ ...state, isLoading: !state.isLoading }),
|
||||||
setBooks: (state, action) => ({ ... state, books: action.payload }),
|
setBooks: (state, action) => ({ ...state, books: action.payload }),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,4 +4,4 @@ module.exports = {
|
||||||
},
|
},
|
||||||
variants: {},
|
variants: {},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
@ -19,7 +15,5 @@
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react"
|
"jsx": "react"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src/**/*"]
|
||||||
"src/**/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<title>sandbox.wpcarro.dev</title>
|
<title>sandbox.wpcarro.dev</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
Loading…
Reference in a new issue