add main html and test files
This commit is contained in:
parent
01835ec2d7
commit
ec63dde2b0
BIN
server_files/dogpepsi.jpg
Normal file
BIN
server_files/dogpepsi.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
35
server_files/dogpepsi.jpg.import
Normal file
35
server_files/dogpepsi.jpg.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/dogpepsi.jpg-600a9f60613039ee9dabc11447d355f1.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://server_files/dogpepsi.jpg"
|
||||
dest_files=[ "res://.import/dogpepsi.jpg-600a9f60613039ee9dabc11447d355f1.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
3
server_files/files.txt
Normal file
3
server_files/files.txt
Normal file
@ -0,0 +1,3 @@
|
||||
first.md 2022-01-06 first article
|
||||
second.md 2021-05-03 second article
|
||||
second.md
|
47
server_files/first.md
Normal file
47
server_files/first.md
Normal file
@ -0,0 +1,47 @@
|
||||
# Importance of Second Opinions
|
||||
|
||||
|
||||
A Mayo Clinic study found that
|
||||
Only 1/10 cases of patients seeking second opinions
|
||||
received confirmation the first diagnosis was complete and correct
|
||||
2/10 cases received a "distinctly different" diagnosis
|
||||
|
||||
Yale Medecine recommends to seek a second opinion
|
||||
when the diagnosis is cancer
|
||||
or
|
||||
when surgery is recommended
|
||||
|
||||
Please tell your loved ones to seek 2nd opinions!
|
||||
|
||||
-----
|
||||
|
||||
First Opinions are often bad:
|
||||
|
||||
- https://newsnetwork.mayoclinic.org/discussion/mayo-clinic-researchers-demonstrate-value-of-second-opinions/
|
||||
- https://newsnetwork.mayoclinic.org/discussion/mayo-clinic-researchers-demonstrate-value-of-second-opinions/
|
||||
|
||||
|
||||
## Key points:
|
||||
|
||||
> The Mayo Clinic study found that as many as
|
||||
> - 9 out of 10 patients seeking a second opinion go home with a new or refined diagnosis.
|
||||
> - 2 out of ten received a “distinctly different” diagnosis.
|
||||
>- only 1 out of 10 referred patients receive confirmation that the original
|
||||
> diagnosis was complete and correct.
|
||||
> This is _out of patients seeking a 2nd opinion_, not patients in general
|
||||
|
||||
Paper referenced by articles found at: https://onlinelibrary.wiley.com/doi/abs/10.1111/jep.12747
|
||||
|
||||
-----
|
||||
|
||||
When to Seek 2nd Opinions according to Yale
|
||||
|
||||
- https://www.yalemedicine.org/news/second-opinions
|
||||
|
||||
Key points:
|
||||
|
||||
> Seek 2nd opinion:
|
||||
> - When the diagnosis is cancer
|
||||
> - **When surgery is recommended**
|
||||
|
||||
-----
|
405
server_files/index.html
Normal file
405
server_files/index.html
Normal file
@ -0,0 +1,405 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Parcel Sandbox</title>
|
||||
<meta charset="UTF-8" />
|
||||
<style></style>
|
||||
</head>
|
||||
<body>
|
||||
<template id="my-link">
|
||||
<style>
|
||||
:host {
|
||||
--background-regular: hsla(196, 61%, 58%, 0.75);
|
||||
--background-active: red;
|
||||
text-decoration: none;
|
||||
color: #18272f;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
:host span {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:host::before {
|
||||
content: "";
|
||||
background-color: var(--background-regular);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 3px;
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
z-index: -1;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
:host(:hover)::before {
|
||||
bottom: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:host([active])::before {
|
||||
background-color: var(--background-active);
|
||||
}
|
||||
</style>
|
||||
|
||||
<span><slot /></span>
|
||||
</template>
|
||||
<template id="my-menu">
|
||||
<style>
|
||||
:host ul,
|
||||
:host li {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
:host nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
<nav>
|
||||
<slot />
|
||||
</nav>
|
||||
</template>
|
||||
<my-menu id="menu">
|
||||
<my-link main href="d">Home</my-link>
|
||||
<h2>Articles</h2>
|
||||
</my-menu>
|
||||
<div id="App"></div>
|
||||
|
||||
<script>
|
||||
//@ts-check
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* UTILITIES
|
||||
*
|
||||
* A few common methods to use in the project
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
const Signal = () => {
|
||||
const listeners = new Set();
|
||||
|
||||
return {
|
||||
remove: listeners.delete.bind(listeners),
|
||||
add(/** @type {(arg:any)=>void} */ listener) {
|
||||
listeners.add(listener);
|
||||
return listeners.delete.bind(listeners, listener);
|
||||
},
|
||||
emit(/** @type {any} */ data) {
|
||||
listeners.forEach((l) => l(data));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const getText = (/** @type {string} */ file) =>
|
||||
fetch(`./${file}`)
|
||||
.then((response) => response.text())
|
||||
.catch((err) => {
|
||||
console.error(`could not find file "${file}"`);
|
||||
throw err;
|
||||
});
|
||||
|
||||
const parseMarkdown = (/** @type {string} */ text) =>
|
||||
text
|
||||
// lists
|
||||
.replace(
|
||||
/^\s*\n((?:\*\s.+\s*\n)+)([^\*])/gm,
|
||||
(_, bullets, next) =>
|
||||
`<ul>${bullets.replace(
|
||||
/^\*\s(.+)/gm,
|
||||
"<li>$1</li>"
|
||||
)}\n</ul>\n\n${next}`
|
||||
)
|
||||
.replace(
|
||||
/^\s*\n((?:\d\..+\s*\n)+)([^\*])/gm,
|
||||
(_, bullets, next) =>
|
||||
`<ol>${bullets.replace(
|
||||
/^\d\.\s(.+)/gm,
|
||||
"<li>$1</li>"
|
||||
)}\n</ol>\n\n${next}`
|
||||
)
|
||||
// blockquotes
|
||||
.replace(/^\>(.+)/gm, "<blockquote>$1</blockquote>")
|
||||
// headers
|
||||
.replace(/(#+)(.+)/g, (_, { length: l }, t) => `<h${l}>${t}</h${l}>`)
|
||||
.replace(/^(.+)\n\=+/gm, "<h1>$1</h1>")
|
||||
.replace(/^(.+)\n\-+/gm, "<h2>$1</h2>")
|
||||
//images
|
||||
.replace(/\!\[([^\]]+)\]\(([^\)]+)\)/g, '<img src="$2" alt="$1" />')
|
||||
//links
|
||||
.replace(
|
||||
/[\[]{1}([^\]]+)[\]]{1}[\(]{1}([^\)\"]+)(\"(.+)\")?[\)]{1}/g,
|
||||
'<a href="$2" title="$4">$1</a>'
|
||||
)
|
||||
//font styles
|
||||
.replace(/[\*\_]{2}([^\*\_]+)[\*\_]{2}/g, "<strong>$1</strong>")
|
||||
.replace(/[\*\_]{1}([^\*\_]+)[\*\_]{1}/g, "<em>$1</em>")
|
||||
.replace(/[\~]{2}([^\~]+)[\~]{2}/g, "<del>$1</del>")
|
||||
//pre
|
||||
.replace(/^\s*\n\`\`\`(([^\s]+))?/gm, '<pre class="$2">')
|
||||
.replace(/^\`\`\`\s*\n/gm, "</pre>\n\n")
|
||||
//code
|
||||
.replace(/[\`]{1}([^\`]+)[\`]{1}/g, "<code>$1</code>")
|
||||
//p
|
||||
.replace(/^\s*(\n)?(.+)/gm, (m) => {
|
||||
return /\<(\/)?(h\d|ul|ol|li|blockquote|pre|img)/.test(m)
|
||||
? m
|
||||
: "<p>" + m + "</p>";
|
||||
})
|
||||
//strip p from pre
|
||||
.replace(/(\<pre.+\>)\s*\n\<p\>(.+)\<\/p\>/gm, "$1$2")
|
||||
.trim();
|
||||
|
||||
const getMarkdown = (/** @type {string} */ file) =>
|
||||
getText(file).then(parseMarkdown);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} tag
|
||||
* @param {Record<string, any>} props
|
||||
* @param {string|Node[]} children
|
||||
* @returns
|
||||
*/
|
||||
const el = (tag = "div", props = {}, children = []) => {
|
||||
const node = document.createElement(tag);
|
||||
Object.keys(props).forEach((key) => {
|
||||
node.setAttribute(key, props[key]);
|
||||
});
|
||||
if (typeof children == "string") {
|
||||
children = [document.createTextNode(children)];
|
||||
}
|
||||
children.forEach((child) => node.appendChild(child));
|
||||
return node;
|
||||
};
|
||||
|
||||
const makeTitelize = (alwaysLowCaps = [], alwaysUpperCaps = []) => {
|
||||
const specials = [...alwaysLowCaps, ...alwaysUpperCaps].reduce(
|
||||
(result, word) =>
|
||||
result.set(new RegExp("\\b" + word + "\\b", "gi"), word),
|
||||
/** @type {Map<RegExp, string>}*/ (new Map())
|
||||
);
|
||||
const titelize = (/** @type {string} */ text) => {
|
||||
text = text
|
||||
.replace(/_-\//g, " ")
|
||||
.replace(/\.\w+$/, "")
|
||||
.replace(/\s+/, " ")
|
||||
.split(" ")
|
||||
.map((word) =>
|
||||
word.length > 1
|
||||
? word[0].toUpperCase() + word.slice(1).toLowerCase()
|
||||
: word
|
||||
)
|
||||
.join(" ");
|
||||
for (const [key, value] of specials) {
|
||||
text = text.replace(key, value);
|
||||
}
|
||||
return text;
|
||||
};
|
||||
return titelize;
|
||||
};
|
||||
|
||||
const titelize = makeTitelize(["the", "a"], ["TV", "ID", "AI"]);
|
||||
|
||||
const Router = (() => {
|
||||
const onRouteChange = Signal();
|
||||
let route = "";
|
||||
|
||||
const set = (/** @type {string} */ newRoute) => {
|
||||
if (newRoute === route) {
|
||||
return false;
|
||||
}
|
||||
window.location.hash = newRoute;
|
||||
route = newRoute;
|
||||
onRouteChange.emit(route);
|
||||
return true;
|
||||
};
|
||||
|
||||
const get = () => window.location.hash.slice(1).replace(/\//gi, "/");
|
||||
|
||||
const is = (href) => href === get();
|
||||
|
||||
window.addEventListener("popstate", () => set(get()));
|
||||
|
||||
return { set, get, is, onRouteChange };
|
||||
})();
|
||||
|
||||
const getTemplateClone = (/** @type {string} */ id) => {
|
||||
const templateModel = /** @type {HTMLTemplateElement} */ (
|
||||
document.getElementById(id)
|
||||
);
|
||||
const template = /** @type {HTMLElement} */ (
|
||||
templateModel.content.cloneNode(true)
|
||||
);
|
||||
return template;
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
* WEB COMPONENTS
|
||||
*
|
||||
* Sources:
|
||||
* https://web.dev/custom-elements-best-practices/
|
||||
* https://googlechromelabs.github.io/howto-components/
|
||||
*
|
||||
* A set of neat components to use in the page
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
class CustomElement extends HTMLElement {
|
||||
/** @type {ShadowRoot} */
|
||||
shadow = this.attachShadow({ mode: "closed" });
|
||||
|
||||
/**
|
||||
* A user may set a property on an instance of an element, before its prototype has been connected to this class.
|
||||
* Will check for any instance properties and run them through the proper class setters.
|
||||
* @param {string} prop
|
||||
*/
|
||||
_syncProperty(prop) {
|
||||
if (this.hasOwnProperty(prop)) {
|
||||
let value = this[prop];
|
||||
delete this[prop];
|
||||
this[prop] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyLink extends CustomElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.shadow.append(getTemplateClone("my-link"));
|
||||
this.shadow.addEventListener("click", this._onClick.bind(this));
|
||||
Router.onRouteChange.add(this.updateActive.bind(this));
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ["href", "active", "main"];
|
||||
}
|
||||
|
||||
_onClick() {
|
||||
if (this.href) {
|
||||
Router.set(this.href);
|
||||
}
|
||||
}
|
||||
|
||||
attributeChangedCallback(property, oldValue, newValue) {
|
||||
if (oldValue === newValue) {
|
||||
return;
|
||||
}
|
||||
this[property] = newValue;
|
||||
}
|
||||
|
||||
updateActive() {
|
||||
if (Router.is(this.href)) {
|
||||
this.setAttribute("active", "");
|
||||
} else {
|
||||
this.removeAttribute("active");
|
||||
}
|
||||
}
|
||||
|
||||
set href(/** @type {string}*/ value) {
|
||||
this.setAttribute("href", value);
|
||||
this.updateActive();
|
||||
}
|
||||
|
||||
get href() {
|
||||
return this.getAttribute("href");
|
||||
}
|
||||
|
||||
set main(/** @type {boolean}*/ value) {
|
||||
if (value) {
|
||||
this.setAttribute("main", "");
|
||||
} else {
|
||||
this.removeAttribute("main");
|
||||
}
|
||||
}
|
||||
|
||||
get main() {
|
||||
return this.hasAttribute("main");
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
["active", "main"].forEach((prop) => this._syncProperty(prop));
|
||||
this.updateActive();
|
||||
if (this.getAttribute("main")) {
|
||||
console.log("sdfsdff");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("my-link", MyLink);
|
||||
|
||||
class MyMenu extends CustomElement {
|
||||
_handled = new Set();
|
||||
constructor() {
|
||||
super();
|
||||
this.shadow.append(getTemplateClone("my-menu"));
|
||||
const slot = this.shadow.querySelector("slot");
|
||||
slot.addEventListener("slotchange", (event) => {
|
||||
for (const child of slot.assignedElements()) {
|
||||
if (this._handled.has(child) || !(child instanceof MyLink)) {
|
||||
continue;
|
||||
}
|
||||
this._handled.add(child);
|
||||
// TODO: pre-fetch
|
||||
//console.log("new child: ", child);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
customElements.define("my-menu", MyMenu);
|
||||
|
||||
/**********************************************************************
|
||||
* MARKDOWN PARSING
|
||||
*********************************************************************/
|
||||
|
||||
const load = (/** @type {string} */ file) =>
|
||||
getMarkdown(file).then((md) => {
|
||||
app.innerHTML = md;
|
||||
});
|
||||
|
||||
/**********************************************************************
|
||||
* BOOSTRAPPING
|
||||
*********************************************************************/
|
||||
|
||||
getText("files.txt").then((lines) => {
|
||||
lines
|
||||
.split(`\n`)
|
||||
.map((line) => {
|
||||
const [file, maybeDate, ...rest] = line.split(/\s/);
|
||||
const href = file.trim();
|
||||
let date = maybeDate ? new Date(maybeDate) : new Date();
|
||||
if (isNaN(date.getTime())) {
|
||||
date = new Date();
|
||||
rest.unshift(maybeDate);
|
||||
}
|
||||
const textContent = rest.length
|
||||
? rest.join(" ").trim()
|
||||
: titelize(file);
|
||||
return { href, date, textContent };
|
||||
})
|
||||
.sort(({ date: a }, { date: b }) => a.getTime() - b.getTime())
|
||||
.forEach(({ href, date, textContent }) => {
|
||||
const link = /** @type {MyLink} */ el(
|
||||
"my-link",
|
||||
{ href },
|
||||
textContent
|
||||
);
|
||||
document.getElementById("menu").appendChild(link);
|
||||
});
|
||||
});
|
||||
|
||||
const app = document.getElementById("App");
|
||||
|
||||
const BLOCKQUOTE = Symbol("blockquote");
|
||||
const PARAGRAPH = Symbol("paragraph");
|
||||
const LIST = Symbol("list");
|
||||
|
||||
Router.onRouteChange.add((route) => load(route));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
1
server_files/index.md
Normal file
1
server_files/index.md
Normal file
@ -0,0 +1 @@
|
||||
# Title
|
BIN
server_files/picture.png
Normal file
BIN
server_files/picture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 MiB |
35
server_files/picture.png.import
Normal file
35
server_files/picture.png.import
Normal file
@ -0,0 +1,35 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/picture.png-f7b364942b19109d5768d9400167481e.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://server_files/picture.png"
|
||||
dest_files=[ "res://.import/picture.png-f7b364942b19109d5768d9400167481e.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
20
server_files/second.md
Normal file
20
server_files/second.md
Normal file
@ -0,0 +1,20 @@
|
||||
# Testing markdown
|
||||
|
||||
This is a test of **markdown** parsing. Again. Because why not?
|
||||
|
||||
Why:
|
||||
|
||||
1. Item1
|
||||
2. Item2
|
||||
|
||||
> Blockquote
|
||||
|
||||
Image:
|
||||
|
||||
![alt text](picture.png)
|
||||
|
||||
```
|
||||
code_block!
|
||||
```
|
||||
|
||||
`code not block`
|
Loading…
Reference in New Issue
Block a user