prettier lint
This commit is contained in:
parent
fdfcd74fe4
commit
fa32427fe1
7 changed files with 231 additions and 165 deletions
|
@ -22,32 +22,32 @@ cache:
|
|||
paths:
|
||||
- node_modules/
|
||||
|
||||
stages: # List of stages for jobs, and their order of execution
|
||||
stages: # List of stages for jobs, and their order of execution
|
||||
- build
|
||||
- test
|
||||
- deploy
|
||||
|
||||
build-job: # This job runs in the build stage, which runs first.
|
||||
build-job: # This job runs in the build stage, which runs first.
|
||||
stage: build
|
||||
script:
|
||||
- npm i
|
||||
- npm run build:svg
|
||||
- npm run build:css
|
||||
|
||||
unit-test-job: # This job runs in the test stage.
|
||||
stage: test # It only starts when the job in the build stage completes successfully.
|
||||
unit-test-job: # This job runs in the test stage.
|
||||
stage: test # It only starts when the job in the build stage completes successfully.
|
||||
script:
|
||||
- echo "Running unit tests..."
|
||||
- npm i
|
||||
- npm test
|
||||
|
||||
lint-test-job: # This job also runs in the test stage.
|
||||
stage: test # It can run at the same time as unit-test-job (in parallel).
|
||||
lint-test-job: # This job also runs in the test stage.
|
||||
stage: test # It can run at the same time as unit-test-job (in parallel).
|
||||
script:
|
||||
- echo "Linting code... TBD"
|
||||
|
||||
deploy-job: # This job runs in the deploy stage.
|
||||
stage: deploy # It only runs when *both* jobs in the test stage complete successfully.
|
||||
deploy-job: # This job runs in the deploy stage.
|
||||
stage: deploy # It only runs when *both* jobs in the test stage complete successfully.
|
||||
environment: production
|
||||
script:
|
||||
- echo "Deploying application... TBD lol"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Getting Started
|
||||
|
||||
* [NodeJS](https://nodejs.org/en/)
|
||||
- [NodeJS](https://nodejs.org/en/)
|
||||
|
||||
```bash
|
||||
npm i # Installs Dependencies
|
||||
|
|
146
app.js
146
app.js
|
@ -1,69 +1,113 @@
|
|||
import express from 'express'
|
||||
import { engine } from 'express-handlebars'
|
||||
import fetchData from './data.js'
|
||||
import express from "express";
|
||||
import { engine } from "express-handlebars";
|
||||
import fetchData from "./data.js";
|
||||
|
||||
const app = express()
|
||||
const data = fetchData()
|
||||
const app = express();
|
||||
const data = fetchData();
|
||||
|
||||
app.engine('handlebars', engine())
|
||||
app.set('view engine', 'handlebars')
|
||||
app.set('views', './src/views')
|
||||
app.engine("handlebars", engine());
|
||||
app.set("view engine", "handlebars");
|
||||
app.set("views", "./src/views");
|
||||
|
||||
app.use(express.static('dist'))
|
||||
app.use(express.static('public'))
|
||||
app.use(express.static("dist"));
|
||||
app.use(express.static("public"));
|
||||
|
||||
const siteName = "Pronoun Monster"
|
||||
const pronounsToDisplayOnHome = 6
|
||||
const siteName = "Pronoun Monster";
|
||||
const pronounsToDisplayOnHome = 6;
|
||||
|
||||
function constructLexicon(nominative, accusative, pronominalPossessive, predicativePossessive, reflexive) {
|
||||
function constructLexicon(
|
||||
nominative,
|
||||
accusative,
|
||||
pronominalPossessive,
|
||||
predicativePossessive,
|
||||
reflexive
|
||||
) {
|
||||
return {
|
||||
nominative: { name: "Nominative", value: nominative},
|
||||
accusative: { name: "Accusative", value: accusative},
|
||||
pronominalPossessive: { name: "Pronominal Possessive", value: pronominalPossessive},
|
||||
predicativePossessive: { name: "Predicative Possessive", value: predicativePossessive},
|
||||
reflexive: { name: "Reflexive", value: reflexive}
|
||||
}
|
||||
nominative: { name: "Nominative", value: nominative },
|
||||
accusative: { name: "Accusative", value: accusative },
|
||||
pronominalPossessive: {
|
||||
name: "Pronominal Possessive",
|
||||
value: pronominalPossessive,
|
||||
},
|
||||
predicativePossessive: {
|
||||
name: "Predicative Possessive",
|
||||
value: predicativePossessive,
|
||||
},
|
||||
reflexive: { name: "Reflexive", value: reflexive },
|
||||
};
|
||||
}
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
app.get("/", (req, res) => {
|
||||
const pageTitle = siteName;
|
||||
const pronounListLimited = data.map(pronounObject => Object.values(pronounObject).join('/')).slice(0, pronounsToDisplayOnHome)
|
||||
res.render('home', { siteName, pageTitle, pronounList: pronounListLimited } )
|
||||
})
|
||||
const pronounListLimited = data
|
||||
.map((pronounObject) => Object.values(pronounObject).join("/"))
|
||||
.slice(0, pronounsToDisplayOnHome);
|
||||
res.render("home", { siteName, pageTitle, pronounList: pronounListLimited });
|
||||
});
|
||||
|
||||
app.get('/list', (req, res) => {
|
||||
app.get("/list", (req, res) => {
|
||||
const pageTitle = "List";
|
||||
const pronounList = data.map(pronounObject => Object.values(pronounObject).join('/'))
|
||||
res.render('list', { siteName, pageTitle, pronounList } )
|
||||
})
|
||||
const pronounList = data.map((pronounObject) =>
|
||||
Object.values(pronounObject).join("/")
|
||||
);
|
||||
res.render("list", { siteName, pageTitle, pronounList });
|
||||
});
|
||||
|
||||
app.get('/:nominative/:accusative/:predicative_possessive/:reflexive', (req, res) => {
|
||||
const {
|
||||
nominative,
|
||||
accusative,
|
||||
predicative_possessive: predicativePossessive,
|
||||
reflexive,
|
||||
} = req.params
|
||||
app.get(
|
||||
"/:nominative/:accusative/:predicative_possessive/:reflexive",
|
||||
(req, res) => {
|
||||
const {
|
||||
nominative,
|
||||
accusative,
|
||||
predicative_possessive: predicativePossessive,
|
||||
reflexive,
|
||||
} = req.params;
|
||||
|
||||
const lexicon = constructLexicon(nominative, accusative, accusative, predicativePossessive, reflexive);
|
||||
const pageTitle = Object.values(lexicon).map(entry => entry.value).join("/") + " - " + siteName;
|
||||
const lexicon = constructLexicon(
|
||||
nominative,
|
||||
accusative,
|
||||
accusative,
|
||||
predicativePossessive,
|
||||
reflexive
|
||||
);
|
||||
const pageTitle =
|
||||
Object.values(lexicon)
|
||||
.map((entry) => entry.value)
|
||||
.join("/") +
|
||||
" - " +
|
||||
siteName;
|
||||
|
||||
res.render('individual', { siteName, pageTitle, lexicon })
|
||||
})
|
||||
res.render("individual", { siteName, pageTitle, lexicon });
|
||||
}
|
||||
);
|
||||
|
||||
app.get('/:nominative/:accusative/:pronominal_possessive/:predicative_possessive/:reflexive', (req, res) => {
|
||||
const {
|
||||
nominative,
|
||||
accusative,
|
||||
pronominal_possessive: pronominalPossessive,
|
||||
predicative_possessive: predicativePossessive,
|
||||
reflexive,
|
||||
} = req.params
|
||||
app.get(
|
||||
"/:nominative/:accusative/:pronominal_possessive/:predicative_possessive/:reflexive",
|
||||
(req, res) => {
|
||||
const {
|
||||
nominative,
|
||||
accusative,
|
||||
pronominal_possessive: pronominalPossessive,
|
||||
predicative_possessive: predicativePossessive,
|
||||
reflexive,
|
||||
} = req.params;
|
||||
|
||||
const lexicon = constructLexicon(nominative, accusative, pronominalPossessive, predicativePossessive, reflexive);
|
||||
const pageTitle = Object.values(lexicon).map(entry => entry.value).join("/") + " - " + siteName;
|
||||
const lexicon = constructLexicon(
|
||||
nominative,
|
||||
accusative,
|
||||
pronominalPossessive,
|
||||
predicativePossessive,
|
||||
reflexive
|
||||
);
|
||||
const pageTitle =
|
||||
Object.values(lexicon)
|
||||
.map((entry) => entry.value)
|
||||
.join("/") +
|
||||
" - " +
|
||||
siteName;
|
||||
|
||||
res.render('individual', { siteName, pageTitle, lexicon })
|
||||
})
|
||||
res.render("individual", { siteName, pageTitle, lexicon });
|
||||
}
|
||||
);
|
||||
|
||||
app.listen(3000)
|
||||
app.listen(3000);
|
||||
|
|
39
data.js
39
data.js
|
@ -1,20 +1,21 @@
|
|||
import fs from 'fs'
|
||||
import fs from "fs";
|
||||
|
||||
const databaseCSV = fs.readFileSync('database.csv', {encoding:'utf8', flag:'r'})
|
||||
const databaseCSV = fs.readFileSync("database.csv", {
|
||||
encoding: "utf8",
|
||||
flag: "r",
|
||||
});
|
||||
|
||||
export function splitNewLines(string) {
|
||||
return string.split(/\n/)
|
||||
return string.split(/\n/);
|
||||
}
|
||||
|
||||
export function cleanupArrayOfStrings(arrayOfStrings) {
|
||||
return arrayOfStrings
|
||||
.map(line => line.trim())
|
||||
.filter(line => line != '')
|
||||
return arrayOfStrings.map((line) => line.trim()).filter((line) => line != "");
|
||||
}
|
||||
|
||||
export function stringCsvToDataObject(string) {
|
||||
let splitString = string.split(',')
|
||||
if (splitString[2].trim() == '') splitString[2] = splitString[1]
|
||||
let splitString = string.split(",");
|
||||
if (splitString[2].trim() == "") splitString[2] = splitString[1];
|
||||
|
||||
const [
|
||||
nominative,
|
||||
|
@ -22,15 +23,23 @@ export function stringCsvToDataObject(string) {
|
|||
pronominalPossessive,
|
||||
predicativePossessive,
|
||||
reflexive,
|
||||
] = cleanupArrayOfStrings(splitString)
|
||||
] = cleanupArrayOfStrings(splitString);
|
||||
|
||||
return {
|
||||
nominative, accusative, pronominalPossessive, predicativePossessive, reflexive
|
||||
}
|
||||
nominative,
|
||||
accusative,
|
||||
pronominalPossessive,
|
||||
predicativePossessive,
|
||||
reflexive,
|
||||
};
|
||||
}
|
||||
|
||||
export default function() {
|
||||
const databaseCSV = fs.readFileSync('database.csv', {encoding:'utf8', flag:'r'})
|
||||
return cleanupArrayOfStrings(splitNewLines(databaseCSV)).map(line => stringCsvToDataObject(line))
|
||||
export default function () {
|
||||
const databaseCSV = fs.readFileSync("database.csv", {
|
||||
encoding: "utf8",
|
||||
flag: "r",
|
||||
});
|
||||
return cleanupArrayOfStrings(splitNewLines(databaseCSV)).map((line) =>
|
||||
stringCsvToDataObject(line)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
110
src/app.css
110
src/app.css
|
@ -3,105 +3,111 @@
|
|||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
/* light */
|
||||
--background: #F8FAF9; /* Sage/Light/2 */
|
||||
--callout: #ECEFED; /* Sage/Light/4 */
|
||||
--stroke: #D7DCDA; /* Sage/Light/7 */
|
||||
--text-shout: #236E4A; /* Green/Dark/8 */
|
||||
--text-murmur: #113123; /* Green/Dark/4 */
|
||||
/* light */
|
||||
--background: #f8faf9; /* Sage/Light/2 */
|
||||
--callout: #ecefed; /* Sage/Light/4 */
|
||||
--stroke: #d7dcda; /* Sage/Light/7 */
|
||||
--text-shout: #236e4a; /* Green/Dark/8 */
|
||||
--text-murmur: #113123; /* Green/Dark/4 */
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
/* dark */
|
||||
--background: #141716; /* Sage/Dark/1 */
|
||||
--callout: #252A27; /* Sage/Dark/4 */
|
||||
--stroke: #393F3C; /* Sage/Dark/7 */
|
||||
--text-shout: #92CEAC; /* Green/Light/7 */
|
||||
--text-murmur: #99A29E; /* Green/Dark/11 */
|
||||
}
|
||||
:root {
|
||||
/* dark */
|
||||
--background: #141716; /* Sage/Dark/1 */
|
||||
--callout: #252a27; /* Sage/Dark/4 */
|
||||
--stroke: #393f3c; /* Sage/Dark/7 */
|
||||
--text-shout: #92ceac; /* Green/Light/7 */
|
||||
--text-murmur: #99a29e; /* Green/Dark/11 */
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--background);
|
||||
color: var(--text-murmur);
|
||||
font-family: Manrope, 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
|
||||
font-weight: 500;
|
||||
background-color: var(--background);
|
||||
color: var(--text-murmur);
|
||||
font-family: Manrope, "Lucida Sans", "Lucida Sans Regular", "Lucida Grande",
|
||||
"Lucida Sans Unicode", Geneva, Verdana, sans-serif;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-weight: 700;
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h2, h3, h4 {
|
||||
color: var(--text-shout);
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
color: var(--text-shout);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: "Redaction", Georgia, 'Times New Roman', Times, serif;
|
||||
font-family: "Redaction", Georgia, "Times New Roman", Times, serif;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: "Redaction 10", Georgia, 'Times New Roman', Times, serif;
|
||||
font-family: "Redaction 10", Georgia, "Times New Roman", Times, serif;
|
||||
}
|
||||
|
||||
footer {
|
||||
border-color: var(--stroke);
|
||||
border-color: var(--stroke);
|
||||
}
|
||||
|
||||
.pronoun-list-title span:not(:last-child):after {
|
||||
content: "/";
|
||||
content: "/";
|
||||
}
|
||||
|
||||
.pronoun-list-link {
|
||||
color: var(--text-shout);
|
||||
text-decoration: underline;
|
||||
color: var(--text-shout);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.pronoun-list-icon {
|
||||
color: var(--text-murmur);
|
||||
color: var(--text-murmur);
|
||||
}
|
||||
|
||||
.pronoun-example-table {
|
||||
border-color: var(--stroke);
|
||||
border-color: var(--stroke);
|
||||
}
|
||||
|
||||
.t-row:not(:last-child) {
|
||||
@apply border-b;
|
||||
border-color: var(--stroke);
|
||||
@apply border-b;
|
||||
border-color: var(--stroke);
|
||||
}
|
||||
|
||||
.t-header {
|
||||
background-color: var(--callout);
|
||||
background-color: var(--callout);
|
||||
}
|
||||
|
||||
.button-cta {
|
||||
background-color: var(--callout);
|
||||
color: var(--text-shout);
|
||||
border-bottom: 2px solid var(--text-shout);
|
||||
border-left: 1px solid var(--text-shout);
|
||||
border-radius: 1rem 0.5rem 1rem 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
display: inline-block;
|
||||
background-color: var(--callout);
|
||||
color: var(--text-shout);
|
||||
border-bottom: 2px solid var(--text-shout);
|
||||
border-left: 1px solid var(--text-shout);
|
||||
border-radius: 1rem 0.5rem 1rem 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.button-cta:not(:active) {
|
||||
margin-bottom: 1px;
|
||||
margin-left: 1px;
|
||||
margin-bottom: 1px;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
.button-cta:active {
|
||||
border-top: 1px solid var(--text-shout);
|
||||
border-right: 1px solid var(--text-shout);
|
||||
transform: translate(-1px, 2px)
|
||||
border-top: 1px solid var(--text-shout);
|
||||
border-right: 1px solid var(--text-shout);
|
||||
transform: translate(-1px, 2px);
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.t-row:not(:last-child) {
|
||||
@apply border-b-0;
|
||||
}
|
||||
.t-row:not(:last-child) .t-cell {
|
||||
@apply border-r;
|
||||
border-color: var(--stroke);
|
||||
}
|
||||
.t-row:not(:last-child) {
|
||||
@apply border-b-0;
|
||||
}
|
||||
.t-row:not(:last-child) .t-cell {
|
||||
@apply border-r;
|
||||
border-color: var(--stroke);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module.exports = {
|
||||
content: ['./src/views/**/*.{handlebars,hbs,html,htm,js}'],
|
||||
content: ["./src/views/**/*.{handlebars,hbs,html,htm,js}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,55 +1,62 @@
|
|||
import fs from 'fs'
|
||||
import test from 'ava'
|
||||
import fetchData, { splitNewLines, cleanupArrayOfStrings, stringCsvToDataObject } from '../data.js'
|
||||
import fs from "fs";
|
||||
import test from "ava";
|
||||
import fetchData, {
|
||||
splitNewLines,
|
||||
cleanupArrayOfStrings,
|
||||
stringCsvToDataObject,
|
||||
} from "../data.js";
|
||||
|
||||
test('splitNewLines', t => {
|
||||
const result = splitNewLines(`foo\nbar`)
|
||||
test("splitNewLines", (t) => {
|
||||
const result = splitNewLines(`foo\nbar`);
|
||||
|
||||
t.deepEqual(result, ['foo', 'bar'])
|
||||
})
|
||||
t.deepEqual(result, ["foo", "bar"]);
|
||||
});
|
||||
|
||||
test('cleanupArrayOfStrings', t => {
|
||||
const result = cleanupArrayOfStrings([
|
||||
'',
|
||||
' foo',
|
||||
'bar ',
|
||||
''
|
||||
])
|
||||
test("cleanupArrayOfStrings", (t) => {
|
||||
const result = cleanupArrayOfStrings(["", " foo", "bar ", ""]);
|
||||
|
||||
t.deepEqual(result, ['foo', 'bar'])
|
||||
})
|
||||
t.deepEqual(result, ["foo", "bar"]);
|
||||
});
|
||||
|
||||
test('clean an array made from a string of new lines', t => {
|
||||
test("clean an array made from a string of new lines", (t) => {
|
||||
const result = cleanupArrayOfStrings(
|
||||
splitNewLines(`
|
||||
foo
|
||||
bar
|
||||
`)
|
||||
)
|
||||
);
|
||||
|
||||
t.deepEqual(result, ['foo', 'bar'])
|
||||
})
|
||||
t.deepEqual(result, ["foo", "bar"]);
|
||||
});
|
||||
|
||||
test('stringCsvToDataObject', t => {
|
||||
const result = stringCsvToDataObject('they,them,them, their,themself')
|
||||
test("stringCsvToDataObject", (t) => {
|
||||
const result = stringCsvToDataObject("they,them,them, their,themself");
|
||||
|
||||
t.deepEqual(result, {
|
||||
nominative: 'they', accusative: 'them', pronominalPossessive: 'them', predicativePossessive: 'their', reflexive: 'themself'
|
||||
})
|
||||
})
|
||||
nominative: "they",
|
||||
accusative: "them",
|
||||
pronominalPossessive: "them",
|
||||
predicativePossessive: "their",
|
||||
reflexive: "themself",
|
||||
});
|
||||
});
|
||||
|
||||
test('stringCsvToDataObject with missing pronominalPossessive', t => {
|
||||
const result = stringCsvToDataObject('they,them,,their,themself')
|
||||
test("stringCsvToDataObject with missing pronominalPossessive", (t) => {
|
||||
const result = stringCsvToDataObject("they,them,,their,themself");
|
||||
|
||||
t.deepEqual(result, {
|
||||
nominative: 'they', accusative: 'them', pronominalPossessive: 'them', predicativePossessive: 'their', reflexive: 'themself'
|
||||
})
|
||||
})
|
||||
nominative: "they",
|
||||
accusative: "them",
|
||||
pronominalPossessive: "them",
|
||||
predicativePossessive: "their",
|
||||
reflexive: "themself",
|
||||
});
|
||||
});
|
||||
|
||||
test('database.csv loads into array of valid data', t => {
|
||||
const data = fetchData()
|
||||
test("database.csv loads into array of valid data", (t) => {
|
||||
const data = fetchData();
|
||||
|
||||
t.truthy(Array.isArray(data))
|
||||
t.is(typeof data[0], 'object')
|
||||
t.is(typeof data[0].nominative, 'string')
|
||||
})
|
||||
t.truthy(Array.isArray(data));
|
||||
t.is(typeof data[0], "object");
|
||||
t.is(typeof data[0].nominative, "string");
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue