Add posts and old grade-calc
Fix small bugs >bad commit
This commit is contained in:
parent
391fff28b1
commit
bfacb23f8a
@ -1,6 +1,7 @@
|
|||||||
import { ChangeEvent, useCallback, useEffect, useRef, useState } from 'react';
|
import { ChangeEvent, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import Fuzzy from './_fuzzy';
|
import Fuzzy from './_fuzzy';
|
||||||
import pages from '../public/pages.json';
|
import pages from '../public/pages.json';
|
||||||
|
import posts from '../public/posts.json';
|
||||||
import style from '../styles/fuzzy.module.css';
|
import style from '../styles/fuzzy.module.css';
|
||||||
|
|
||||||
function FuzzyBar(): JSX.Element {
|
function FuzzyBar(): JSX.Element {
|
||||||
@ -13,9 +14,15 @@ function FuzzyBar(): JSX.Element {
|
|||||||
|
|
||||||
let fuzz: Fuzzy | null = null;
|
let fuzz: Fuzzy | null = null;
|
||||||
|
|
||||||
|
let entries = [...pages];
|
||||||
|
|
||||||
|
for (const [k,v] of posts.entries()) {
|
||||||
|
entries.push({title: v.title, link: `posts/${v.slug}`});
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fuzz = new Fuzzy({
|
fuzz = new Fuzzy({
|
||||||
pages: pages,
|
pages: entries,
|
||||||
searchField: searchField,
|
searchField: searchField,
|
||||||
searchValue: searchValue,
|
searchValue: searchValue,
|
||||||
resultsValue: resultsValue,
|
resultsValue: resultsValue,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import FuzzyBar from './fuzzy-bar';
|
import FuzzyBar from './fuzzy-bar';
|
||||||
import Logo from '../public/logo.svg';
|
|
||||||
import Meta from './meta';
|
import Meta from './meta';
|
||||||
import Title from './title';
|
import Title from './title';
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import style from '../styles/title.module.css';
|
import style from '../styles/title.module.css';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
type propsObj = {
|
type propsObj = {
|
||||||
name: string,
|
name: string,
|
||||||
|
43
lib/slug.ts
Normal file
43
lib/slug.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import fs from 'fs'
|
||||||
|
import matter from 'gray-matter';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
const postsDirectory = join(process.cwd(), 'posts');
|
||||||
|
|
||||||
|
export function getPost(rawslug: string, filter: Array<any> = []) {
|
||||||
|
const slug = rawslug.replace(/\.md$/, '');
|
||||||
|
const path = join(postsDirectory, `${slug}.md`);
|
||||||
|
const file = fs.readFileSync(path, 'utf-8');
|
||||||
|
const { data, content } = matter(file);
|
||||||
|
|
||||||
|
if (data['last_updated'] === undefined)
|
||||||
|
data['last_updated'] = data['created_at'];
|
||||||
|
|
||||||
|
if (filter.length === 0)
|
||||||
|
return { ...data, content, slug, rawslug };
|
||||||
|
|
||||||
|
let post: { slug?: string, rawslug?: string, content?: string, title?: string } | any = {};
|
||||||
|
for (const [_, entry] of filter.entries()) {
|
||||||
|
if (entry === 'slug')
|
||||||
|
post[entry] = slug;
|
||||||
|
|
||||||
|
if (entry === 'rawslug')
|
||||||
|
post[entry] = rawslug;
|
||||||
|
|
||||||
|
if (entry === 'content')
|
||||||
|
post[entry] = content;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof data[entry] !== 'undefined') {
|
||||||
|
post[entry] = data[entry]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return post;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAllPosts(filter: Array<any> = []) {
|
||||||
|
const files = fs.readdirSync(postsDirectory);
|
||||||
|
|
||||||
|
return files.map(file => { return getPost(file, filter) });
|
||||||
|
}
|
690
package-lock.json
generated
690
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/react": "^17.0.37",
|
"@types/react": "^17.0.37",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
|
"gray-matter": "^4.0.3",
|
||||||
"next": "^11.1.3",
|
"next": "^11.1.3",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
@ -19,6 +20,7 @@
|
|||||||
"@types/react-dom": "^17.0.11",
|
"@types/react-dom": "^17.0.11",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-next": "^11.1.2",
|
"eslint-config-next": "^11.1.2",
|
||||||
"typescript": "^4.5.2"
|
"typescript": "^4.5.2",
|
||||||
|
"ts-node": "^10.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,11 @@ function AboutPage() {
|
|||||||
I do not really know, at least the content I put here. I guess I wanted a place on the web where I wanted to put everything I think is worth looking at some point in the future.
|
I do not really know, at least the content I put here. I guess I wanted a place on the web where I wanted to put everything I think is worth looking at some point in the future.
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
It seems wise to have things up here even though they may embarrass me at some point in the future, as many of the things I have done in the past have. Especially the web sites I made in high school. I will never forget those.
|
It seems wise to have things up here even though they may embarrass me at some point in the future, as many of the things I have done in the past have.
|
||||||
<hr />
|
|
||||||
Got any questions, concerns, or issues? Feel free to contact me via my email: <code>lambdapaul [at] pm [dot] me</code>.
|
Got any questions, concerns, or issues? Feel free to contact me via my email: <code>lambdapaul [at] pm [dot] me</code>.
|
||||||
</section>
|
</section>
|
||||||
<section className='block'>
|
<section className='block'>
|
||||||
<ReactMarkdown>{ReadmeMd}</ReactMarkdown>
|
<ReactMarkdown>{ReadmeMd.replace(/#{1,5} /g, (s: string) => {return `#${s}`})}</ReactMarkdown>
|
||||||
</section>
|
</section>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { ReactElement, useState } from 'react';
|
import React, { ReactElement, useEffect, useState } from 'react';
|
||||||
import Layout from '../../components/layout';
|
import Layout from '../../components/layout';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import GradeCalc from '../../components/_gc';
|
import GradeCalc from '../../components/_gc';
|
||||||
@ -77,9 +77,22 @@ function GradeCalcPage() {
|
|||||||
// export default GradeCalcPage;
|
// export default GradeCalcPage;
|
||||||
|
|
||||||
export default function WIP() {
|
export default function WIP() {
|
||||||
|
useEffect(() => {
|
||||||
|
const script = document.createElement('script');
|
||||||
|
|
||||||
|
script.src = '/grade-calc/vanilla.js';
|
||||||
|
script.async = true;
|
||||||
|
|
||||||
|
document.body.appendChild(script);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.body.removeChild(script);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout name='Grade Calc' title='[WIP] Grade Calculator'>
|
<Layout name='Grade Calc' title='[WIP] Grade Calculator'>
|
||||||
<section className='block' style={{textAlign: 'center'}}>
|
<section className='grade-calc'>
|
||||||
Check back later as the port of this page is a Work in Progress.
|
Check back later as the port of this page is a Work in Progress.
|
||||||
</section>
|
</section>
|
||||||
</Layout>);
|
</Layout>);
|
||||||
|
@ -2,29 +2,46 @@ import Link from 'next/link';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Layout from '../components/layout';
|
import Layout from '../components/layout';
|
||||||
import Pages from '../public/pages.json';
|
import Pages from '../public/pages.json';
|
||||||
|
import cachePostLinkData from '../util/post-cache';
|
||||||
|
|
||||||
// import { GetStaticProps } from 'next';
|
|
||||||
|
|
||||||
function HomePage() {
|
function HomePage({posts}: any) {
|
||||||
|
Pages.sort((x, y) => { return ('' + x.title).localeCompare(y.title) });
|
||||||
return (
|
return (
|
||||||
<Layout name='' title='PaulW.XYZ'>
|
<Layout name='' title='PaulW.XYZ'>
|
||||||
<section className='block' style={{ textAlign: 'center' }}>
|
<section className='block'>
|
||||||
<div className='h2'>Welcome to my website!</div> {
|
<div className='h2'>Welcome!</div>
|
||||||
|
{
|
||||||
Pages.map(obj => {
|
Pages.map(obj => {
|
||||||
return <div key='' className='h3'>
|
return <div key='' className='h5'>
|
||||||
<Link href={obj.link}>
|
<Link href={obj.link}>
|
||||||
<a>{obj.title}</a>
|
<a>{obj.title}{obj.link.match('^http*')? ' ↗' : ''}</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</section>
|
</section>
|
||||||
|
<section className='block'>
|
||||||
|
<div className='h2'>Posts</div>
|
||||||
|
<div>
|
||||||
|
{posts?.map((post: any) => {
|
||||||
|
return <div key={post.slug} className='h5'>
|
||||||
|
[{ (new Date(post.last_updated)).toLocaleString()}] <Link href={`posts/${post.slug}`}>
|
||||||
|
{post.title}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HomePage;
|
export async function getStaticProps() {
|
||||||
|
// make this webpack plugin
|
||||||
|
return {
|
||||||
|
props: {posts: cachePostLinkData()}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// export async function getStaticProps(context): GetStaticProps {
|
export default HomePage;
|
||||||
|
|
||||||
// }
|
|
42
pages/posts/[page].tsx
Normal file
42
pages/posts/[page].tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import Layout from '../../components/layout';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import { getAllPosts, getPost } from '../../lib/slug';
|
||||||
|
import ReactMarkdown from 'react-markdown';
|
||||||
|
import Image from 'next/image';
|
||||||
|
|
||||||
|
function Post({post} : any) { // eh
|
||||||
|
const router = useRouter();
|
||||||
|
return (
|
||||||
|
<Layout name={post.title} title={post.title} ancestors={[{name:'Posts', path: 'posts'}]}>
|
||||||
|
<section className='block'>
|
||||||
|
{post.cover ? <Image width={640} height={360} layout="intrinsic" src={`/assets/images/${post.cover}`} alt={`${post.title} Cover Image`} /> : ''}
|
||||||
|
<ReactMarkdown>{post.content}</ReactMarkdown>
|
||||||
|
</section>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStaticProps({params}: any) {
|
||||||
|
const post = getPost(params.page);
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {post}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const posts = getAllPosts();
|
||||||
|
return {
|
||||||
|
paths: posts.map(post => {
|
||||||
|
return {
|
||||||
|
params: {
|
||||||
|
page: post.slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
fallback: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default Post;
|
32
pages/posts/index.tsx
Normal file
32
pages/posts/index.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import Link from 'next/link';
|
||||||
|
import React from 'react';
|
||||||
|
import Layout from '../../components/layout';
|
||||||
|
import { getAllPosts } from '../../lib/slug';
|
||||||
|
import Pages from '../../public/pages.json';
|
||||||
|
import cachePostLinkData from '../../util/post-cache';
|
||||||
|
|
||||||
|
|
||||||
|
function HomePage({posts}: any) {
|
||||||
|
Pages.sort((x, y) => { return ('' + x.title).localeCompare(y.title) });
|
||||||
|
return (
|
||||||
|
<Layout name='Posts'>
|
||||||
|
{posts.map((post: any) => {
|
||||||
|
return <section key='' className='h5 block'>
|
||||||
|
<Link href={`posts/${post.slug}`}>
|
||||||
|
{post.title}
|
||||||
|
</Link>
|
||||||
|
<div>[{ (new Date(post.last_updated)).toLocaleString()}]</div>
|
||||||
|
</section>
|
||||||
|
})}
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStaticProps() {
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {posts: cachePostLinkData()}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HomePage;
|
14
posts/thoughts-on-baba-is-you.md
Normal file
14
posts/thoughts-on-baba-is-you.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
title: Thoughts on Baba Is You
|
||||||
|
created_at: '2021-10-30T00:43:00.000Z'
|
||||||
|
cover: 'baba_is_you_screencap.png'
|
||||||
|
---
|
||||||
|
|
||||||
|
Just when I thought this game exhausted everything it has to offer, it introduces a new mechanic.
|
||||||
|
Just when I thought I mastered this game, it introduces something new and adds to the complexity.
|
||||||
|
|
||||||
|
I do not know how to compare it to a typical puzzle game because this game is in a sub-genre on its own. You write the rules to your suiting. However many level constrain the rules so you have to work with the ones that level does not have "locked." The early levels are relatively straight-forward, as they act as tutorials. But the difficulty curve goes up and up until you hit a roadblock and get stuck on it for hours. That is when you play a different level. Yes, the game has this over-world similar to the one in Super Mario World where you access levels and sub-worlds. Beating a level unlocks the surrounding locked levels and a dandelion-looking thing (it is really never explained). Sub-worlds are also unlocked by beating levels and collecting those dandelions. There are other collectibles too that are awarded based on set criteria but that would be too much information for new players and for a review.
|
||||||
|
|
||||||
|
Do not let the cutesy art style and music in the trailers and other promotional media distract you. This game is extremely difficult. But the moment a solution clicks in a level, there is no better feeling.
|
||||||
|
|
||||||
|
Speaking of music, I feel it is the weakest part of the game. The main theme is simple but catchy and the rest are somewhat forget-able.
|
BIN
public/assets/images/baba_is_you_screencap.png
Normal file
BIN
public/assets/images/baba_is_you_screencap.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 140 KiB |
268
public/grade-calc/vanilla.js
Normal file
268
public/grade-calc/vanilla.js
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
(()=>{
|
||||||
|
const cont = `
|
||||||
|
<div class="about-container block">
|
||||||
|
<h2>About</h2>
|
||||||
|
Check out the <a href="https://github.com/lambdapaul/www/blob/master/public/grade-calc/README.md">README.md</a> file
|
||||||
|
to learn more about the configuration structure.
|
||||||
|
<h3>Usage</h3>
|
||||||
|
<ol>
|
||||||
|
<li>Either configure the calculator using the text box below or load one from the existing JSON files to
|
||||||
|
generate one.</li>
|
||||||
|
<li>Click <code>Generate</code>.</li>
|
||||||
|
<li>Enter the input values.</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
<div class="calculator-container block">
|
||||||
|
</div>
|
||||||
|
<div class="json-textarea block">
|
||||||
|
<h2>Configuration</h2>
|
||||||
|
<h3>Load config from file</h3>
|
||||||
|
<ul>
|
||||||
|
<li><a href="javascript:void(0)" onclick="loadConfig('/grade-calc/config/map2302.json')">MAP2302 - ODE I Fall 2019 (map2302.json)</a></li>
|
||||||
|
<li><a href="javascript:void(0)" onclick="loadConfig('/grade-calc/config/eee3307c.json')">EEE3307C - Electronics I Spring 2021 (eee3307c.json)</a></li>
|
||||||
|
<li><a href="javascript:void(0)" onclick="loadConfig('/grade-calc/config/eel4742c.json')">EEL4742C - Embedded Systems Spring 2021 (eel4742c.json)</a></li>
|
||||||
|
<li><a href="javascript:void(0)" onclick="loadConfig('/grade-calc/config/eel4781.json')">EEL4781 - Computer Comm. Networks Spring 2021 (eel4781.json)</a></li>
|
||||||
|
</ul>
|
||||||
|
<div class="button-container">
|
||||||
|
<button class="button" onclick="generate()">Generate →</button>
|
||||||
|
</div>
|
||||||
|
<textarea id="json" id="" rows="30"></textarea>
|
||||||
|
|
||||||
|
</div><span class="clear"></span>`;
|
||||||
|
document.querySelector('.grade-calc').innerHTML = cont;
|
||||||
|
})(); // eh
|
||||||
|
|
||||||
|
function generate() {
|
||||||
|
let calcSection = document.querySelector(".calculator-container");
|
||||||
|
calcSection.innerHTML = "";
|
||||||
|
try {
|
||||||
|
conf = JSON.parse(document.getElementById("json").value);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
calcSection.innerHTML = e;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let cb = (out) => {
|
||||||
|
for (let o of out) {
|
||||||
|
calcSection.appendChild(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gc = new __GradeCalc(conf, cb);
|
||||||
|
|
||||||
|
calcSection.appendChild(gc.elemTotal);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadConfig(filename) {
|
||||||
|
var client = new XMLHttpRequest();
|
||||||
|
client.open('GET', filename);
|
||||||
|
client.onreadystatechange = function () {
|
||||||
|
document.getElementById("json").value = (client.responseText);
|
||||||
|
}
|
||||||
|
client.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
class __GradeCalc {
|
||||||
|
maxscore = 0;
|
||||||
|
sections = [];
|
||||||
|
inputSection = [];
|
||||||
|
outputSection = [];
|
||||||
|
fields = [];
|
||||||
|
grades = [];
|
||||||
|
ugrades = [];
|
||||||
|
both = false;
|
||||||
|
totalOutput = null;
|
||||||
|
|
||||||
|
constructor(config, outCallback) {
|
||||||
|
this.totalOutput = document.createElement("div");
|
||||||
|
let dConfig = JSON.parse(JSON.stringify(config)); // dirty clone
|
||||||
|
let sanConfig = [];
|
||||||
|
for (let conf of dConfig) {
|
||||||
|
if (conf.percentage === undefined || conf.name === undefined)
|
||||||
|
continue;
|
||||||
|
if (conf.title === undefined)
|
||||||
|
conf.title = conf.name[0].toUpperCase() + conf.name.slice(1);
|
||||||
|
sanConfig.push(conf);
|
||||||
|
}
|
||||||
|
this.config = sanConfig;
|
||||||
|
for (let [i, conf] of this.config.entries()) {
|
||||||
|
this.maxscore += conf.percentage;
|
||||||
|
|
||||||
|
this.inputSection[i] = [];
|
||||||
|
this.outputSection[i] = document.createElement("div");
|
||||||
|
|
||||||
|
if (conf.bothMethods) {
|
||||||
|
this.both = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sections[i] = (this.createSection(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let [k, v] of this.fields.entries()) {
|
||||||
|
for (let field of v) {
|
||||||
|
this.addInputEventListener(k, field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outCallback(this.sections);
|
||||||
|
}
|
||||||
|
|
||||||
|
createSection(id) {
|
||||||
|
let conf = this.config[id];
|
||||||
|
|
||||||
|
var section = document.createElement("div");
|
||||||
|
section.classList.add(conf.name);
|
||||||
|
|
||||||
|
var heading = document.createElement("h2");
|
||||||
|
heading.innerHTML = `${conf.title} (${conf.percentage}%)`;
|
||||||
|
|
||||||
|
section.appendChild(heading);
|
||||||
|
|
||||||
|
if (conf.info !== undefined)
|
||||||
|
section.appendChild(document.createTextNode(conf.info));
|
||||||
|
|
||||||
|
this.fields[id] = [];
|
||||||
|
if (conf.points !== undefined) {
|
||||||
|
for (var i = 0; i < conf.points.length; i++) {
|
||||||
|
section.appendChild(this.createInputSection(id, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
section.appendChild(this.createInputSection(id, 0, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
section.appendChild(this.outputSection[id]);
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
|
||||||
|
createInputSection(sectId, inputId, soleInput = false) {
|
||||||
|
let conf = this.config[sectId];
|
||||||
|
let inputSection = document.createElement("div");
|
||||||
|
inputSection.classList.add("input-section");
|
||||||
|
|
||||||
|
let label = document.createElement("label");
|
||||||
|
if (soleInput)
|
||||||
|
label.innerHTML = `${conf.title} Score: `;
|
||||||
|
else
|
||||||
|
label.innerHTML = `${conf.title} ${inputId + 1} Score: `;
|
||||||
|
|
||||||
|
let field = document.createElement("input");
|
||||||
|
field.classList.add(`input`);
|
||||||
|
field.classList.add(`${conf.name}-score`);
|
||||||
|
this.fields[sectId][inputId] = field;
|
||||||
|
|
||||||
|
let suffix = (soleInput) ? "%" : ` / ${conf.points[inputId]} pts`;
|
||||||
|
|
||||||
|
inputSection.appendChild(label);
|
||||||
|
inputSection.appendChild(field);
|
||||||
|
inputSection.appendChild(document.createTextNode(suffix));
|
||||||
|
|
||||||
|
this.inputSection[sectId][inputId] = inputSection;
|
||||||
|
return inputSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
addInputEventListener(id, field, event = "keyup") {
|
||||||
|
let conf = this.config[id];
|
||||||
|
field.addEventListener(event, () => {
|
||||||
|
if (conf.output !== undefined && conf.output)
|
||||||
|
this.showSectionGrade(id);
|
||||||
|
this.showTotalGrade();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateSectionGrade(id, unweighted = false) {
|
||||||
|
let conf = this.config[id];
|
||||||
|
let fields = this.fields[id];
|
||||||
|
if (fields === undefined)
|
||||||
|
return;
|
||||||
|
if (conf.points === undefined) {
|
||||||
|
return parseFloat(fields[0].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let total = 0;
|
||||||
|
|
||||||
|
if (unweighted) {
|
||||||
|
let counter = 0;
|
||||||
|
for (let [i, field] of fields.entries()) {
|
||||||
|
let val = parseFloat(field.value);
|
||||||
|
if (isNaN(val))
|
||||||
|
continue;
|
||||||
|
total += val / conf.points[i];
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (total / counter * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
total = fields.reduce((acc, cur) => {
|
||||||
|
let c = parseFloat(cur.value);
|
||||||
|
if (isNaN(c))
|
||||||
|
return acc;
|
||||||
|
return acc + parseFloat(c);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
let max_total = 0;
|
||||||
|
for (let [i, field] of conf.points.entries()) {
|
||||||
|
if (isNaN(parseFloat(fields[i].value)))
|
||||||
|
continue;
|
||||||
|
max_total += field;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (total / max_total * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
showSectionGrade(id) {
|
||||||
|
let conf = this.config[id];
|
||||||
|
let grade = this.calculateSectionGrade(id);
|
||||||
|
let ugrade = this.calculateSectionGrade(id, true);
|
||||||
|
|
||||||
|
|
||||||
|
this.grades[id] = grade * parseFloat(conf.percentage) / 100;
|
||||||
|
this.ugrades[id] = ugrade * parseFloat(conf.percentage) / 100;
|
||||||
|
|
||||||
|
grade = !isNaN(grade) ? grade.toFixed(2) : "...";
|
||||||
|
ugrade = !isNaN(ugrade) ? ugrade.toFixed(2) : "...";
|
||||||
|
if (conf.bothMethods) {
|
||||||
|
this.outputSection[id].innerHTML
|
||||||
|
= `Score (weighted): ${grade}%<br> Score (unweighted): ${ugrade}%`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.outputSection[id].innerHTML = `Score: ${grade}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
showTotalGrade() {
|
||||||
|
for (let [k, conf] of this.config.entries()) {
|
||||||
|
if (!conf.output) {
|
||||||
|
this.grades[k] = this.calculateSectionGrade(k) * parseFloat(conf.percentage) / 100;
|
||||||
|
this.ugrades[k] = this.calculateSectionGrade(k, true) * parseFloat(conf.percentage) / 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let grade = this.grades.reduce((a, c) => {
|
||||||
|
if (isNaN(c))
|
||||||
|
return a;
|
||||||
|
return a + c
|
||||||
|
}, 0);
|
||||||
|
let ugrade = this.ugrades.reduce((a, c) => {
|
||||||
|
if (isNaN(c))
|
||||||
|
return a;
|
||||||
|
return a + c
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
grade = !isNaN(grade) ? grade.toFixed(2) : "...";
|
||||||
|
ugrade = !isNaN(ugrade) ? ugrade.toFixed(2) : "...";
|
||||||
|
if (this.both) {
|
||||||
|
this.totalOutput.innerHTML
|
||||||
|
= `Total Score (weighted): ${grade}%<br> Total Score (unweighted): ${ugrade}%`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.totalOutput.innerHTML = `Total Score: ${grade}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get elemTotal() {
|
||||||
|
return this.totalOutput;
|
||||||
|
}
|
||||||
|
}
|
@ -9,5 +9,6 @@
|
|||||||
{"title":"Mastodon", "link": "https://mastodon.social/@lambdapaul"},
|
{"title":"Mastodon", "link": "https://mastodon.social/@lambdapaul"},
|
||||||
{"title":"Matrix", "link": "https://matrix.to/#/@lambdapaul:matrix.org"},
|
{"title":"Matrix", "link": "https://matrix.to/#/@lambdapaul:matrix.org"},
|
||||||
{"title":"Keybase", "link": "https://keybase.io/lambdapaul"},
|
{"title":"Keybase", "link": "https://keybase.io/lambdapaul"},
|
||||||
{"title":"Playlists", "link": "/playlists"}
|
{"title":"Playlists", "link": "/playlists"},
|
||||||
|
{"title":"Posts", "link": "/posts"}
|
||||||
]
|
]
|
||||||
|
1
public/posts.json
Normal file
1
public/posts.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{"title":"Steam Info","slug":"steam-info","last_updated":"2022-02-14T09:18:29.604Z"},{"title":"Thoughts on Baba Is You","slug":"thoughts-on-baba-is-you","last_updated":"2021-10-29T04:00:00.000Z"}]
|
@ -1,61 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "root",
|
|
||||||
"domain": "paulw.xyz",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"name": "resources",
|
|
||||||
"type": "route"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "recommended",
|
|
||||||
"type": "route"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "playlists",
|
|
||||||
"type": "route"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "grade-calc",
|
|
||||||
"type": "route",
|
|
||||||
"text": "Grade Calculator",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"name": "readme",
|
|
||||||
"type": "route",
|
|
||||||
"text": "Grade Calculator Read Me"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "about",
|
|
||||||
"type": "route"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "github",
|
|
||||||
"type": "external",
|
|
||||||
"text": "GitHub",
|
|
||||||
"url": "https://github.com/LambdaPaul"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "gitlab",
|
|
||||||
"type": "external",
|
|
||||||
"text": "GitLab",
|
|
||||||
"url": "https://gitlab.com/LambdaPaul"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "mastodon",
|
|
||||||
"type": "external",
|
|
||||||
"url": "https://mastodon.social/@lambdapaul"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "keybase",
|
|
||||||
"type": "external",
|
|
||||||
"url": "https://keybase.io/lambdapaul"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "matrix",
|
|
||||||
"type": "external",
|
|
||||||
"url": "https://matrix.to/#/@lambdapaul:matrix.org"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
# Site.json File Specification
|
|
||||||
|
|
||||||
This is a very basic site structure specification used to generate some of the navigations pages and components of the website.
|
|
||||||
|
|
||||||
## Definitions
|
|
||||||
|
|
||||||
### Member
|
|
||||||
|
|
||||||
### Website
|
|
||||||
|
|
||||||
## Attributes
|
|
||||||
|
|
||||||
These are the keys to the object definition used to define the website. Not all of the attributes will be read by the application as they are dependent on the type of member. However, if they are, they must conform to this document.
|
|
||||||
|
|
||||||
### `name`
|
|
||||||
|
|
||||||
Name is one of the two required attributes for each member, along with type.
|
|
||||||
|
|
||||||
### `type`
|
|
||||||
|
|
||||||
|
|
||||||
### `children`
|
|
||||||
|
|
||||||
Children is used to define sub-members of the current member.
|
|
||||||
|
|
||||||
### `text`
|
|
||||||
|
|
||||||
Text is used tto override the string that the capitalization of the name results in. If a change is not required, this may be omitted.
|
|
||||||
|
|
||||||
### `url`
|
|
||||||
|
|
||||||
### `domain`
|
|
||||||
|
|
||||||
## Types
|
|
||||||
|
|
||||||
The types are the different kinds of members that the page can have. They are defined with the `type` attribute. The current list is tentative.
|
|
||||||
|
|
||||||
### `root`
|
|
||||||
|
|
||||||
### `directory`
|
|
||||||
|
|
||||||
### `route`
|
|
||||||
|
|
||||||
### `external`
|
|
@ -5,6 +5,7 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background-color: rgba(0, 0, 0, 0.9);
|
background-color: rgba(0, 0, 0, 0.9);
|
||||||
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search {
|
.search {
|
||||||
|
@ -150,9 +150,32 @@ section {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.block {
|
.block {
|
||||||
margin: 2rem;
|
margin: 0 2rem;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
/* box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); */
|
/* box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); */
|
||||||
border: 1px solid #ffffff;
|
border: 1px solid #ffffff;
|
||||||
border-radius: 1rem;
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block:first-of-type {
|
||||||
|
border-top-right-radius: 1rem;
|
||||||
|
border-top-left-radius: 1rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block:last-of-type {
|
||||||
|
border-bottom: 1px solid #ffffff;
|
||||||
|
border-bottom-right-radius: 1rem;
|
||||||
|
border-bottom-left-radius: 1rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
overflow-x: scroll;
|
||||||
|
max-width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
font-size: 1rem;
|
||||||
|
padding: 0.1rem 0.5rem;
|
||||||
|
vertical-align: bottom;
|
||||||
}
|
}
|
14
util/post-cache.ts
Normal file
14
util/post-cache.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import { getAllPosts } from '../lib/slug';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
|
const publicDir = join(process.cwd(), 'public');
|
||||||
|
|
||||||
|
export default function cachePostLinkData() {
|
||||||
|
const posts = getAllPosts(['title', 'slug', 'last_updated']);
|
||||||
|
fs.writeFile(`${publicDir}/posts.json`, JSON.stringify(posts), (e) => {
|
||||||
|
if (e)
|
||||||
|
console.error(e);
|
||||||
|
});
|
||||||
|
return posts;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user