updatge
16
app/DJDonate.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { defineComponent } from "vue";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "dj-donate",
|
||||||
|
setup: () => {
|
||||||
|
const imgsrc =
|
||||||
|
"https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=djledda&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff";
|
||||||
|
return () => (
|
||||||
|
<div class="dj-donate">
|
||||||
|
<a href="https://www.buymeacoffee.com/djledda">
|
||||||
|
<img src={imgsrc} />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -14,7 +14,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
return () => (
|
return () => (
|
||||||
<a href="#" onClick={clickMail}>
|
<a href="#" onClick={clickMail}>
|
||||||
{ slots.default ? slots.default() : 'dan.j.ledda [at] gmail [dot] com' }
|
{slots.default ? slots.default() : "dan.j.ledda [at] gmail [dot] com"}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
80
app/DJTooltip.tsx
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import { watchEffect, watch, onMounted, type CSSProperties, defineComponent, ref } from "vue";
|
||||||
|
|
||||||
|
const carrierStyle = {
|
||||||
|
opacity: "0",
|
||||||
|
display: "block",
|
||||||
|
pointerEvents: "none",
|
||||||
|
backgroundColor: "black",
|
||||||
|
border: "white solid 1px",
|
||||||
|
color: "white",
|
||||||
|
padding: "10px",
|
||||||
|
position: "absolute",
|
||||||
|
zIndex: "1",
|
||||||
|
overflow: "hidden",
|
||||||
|
height: "0",
|
||||||
|
width: "0",
|
||||||
|
transition: "opacity 200ms, height 200ms, width 200ms",
|
||||||
|
} satisfies CSSProperties;
|
||||||
|
|
||||||
|
const textCarrierStyle = {
|
||||||
|
fontSize: '16px',
|
||||||
|
fontFamily: "Roboto, serif",
|
||||||
|
display: "block",
|
||||||
|
overflow: "hidden",
|
||||||
|
} satisfies CSSProperties;
|
||||||
|
|
||||||
|
const defaultWidth = 350;
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "dj-sexy-tooltip",
|
||||||
|
props: {
|
||||||
|
tooltip: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props, { slots, attrs }) {
|
||||||
|
const active = ref(false);
|
||||||
|
|
||||||
|
const carrier = ref<HTMLElement | null>(null);
|
||||||
|
const textCarrier = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
document.addEventListener("mousemove", (event) => {
|
||||||
|
const pos = { x: event.pageX, y: event.pageY };
|
||||||
|
if (carrier.value && getComputedStyle(carrier.value).opacity !== "0") {
|
||||||
|
if (pos.x + 15 + carrier.value.clientWidth <= document.body.scrollWidth) {
|
||||||
|
carrier.value.style.left = (pos.x + 15) + "px";
|
||||||
|
} else {
|
||||||
|
carrier.value.style.left = (document.body.scrollWidth - carrier.value.clientWidth - 5) + "px";
|
||||||
|
}
|
||||||
|
if (pos.y + carrier.value.clientHeight <= document.body.scrollHeight) {
|
||||||
|
carrier.value.style.top = pos.y + "px";
|
||||||
|
} else {
|
||||||
|
carrier.value.style.top = (document.body.scrollHeight - carrier.value.clientHeight - 5) + "px";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
if (carrier.value) {
|
||||||
|
carrier.value.style.height = active.value ? '16px' : '0';
|
||||||
|
carrier.value.style.opacity = active.value ? '1' : '0';
|
||||||
|
carrier.value.style.width = active.value ? '350px' : '0';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => <>
|
||||||
|
<div class="tooltip-container" {...attrs}
|
||||||
|
onMouseenter={() => { active.value = true; }}
|
||||||
|
onMouseleave={() => { active.value = false; }}
|
||||||
|
>
|
||||||
|
{slots.default && <slots.default />}
|
||||||
|
</div>
|
||||||
|
<div style={carrierStyle} ref={carrier}>
|
||||||
|
<span style={textCarrierStyle}>{props.tooltip}</span>
|
||||||
|
</div>
|
||||||
|
</>;
|
||||||
|
},
|
||||||
|
});
|
||||||
14
app/api.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export type DJAPIEndpoint = "/rp-articles";
|
||||||
|
|
||||||
|
export interface DJAPIResultMap extends Record<DJAPIEndpoint, unknown> {
|
||||||
|
"/rp-articles": { slug: string; name: string }[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DJAPIResult = DJAPIResultMap[DJAPIEndpoint];
|
||||||
|
|
||||||
|
export default async function getDJAPI<T extends DJAPIEndpoint>(
|
||||||
|
hostUrl: string,
|
||||||
|
endpoint: T,
|
||||||
|
): Promise<DJAPIResultMap[typeof endpoint]> {
|
||||||
|
return await (await fetch(`${hostUrl}/api${endpoint}`)).json();
|
||||||
|
}
|
||||||
@@ -1,194 +1,7 @@
|
|||||||
import { defineComponent, computed, ref } from 'vue';
|
import { computed, defineComponent, ref } from "vue";
|
||||||
|
|
||||||
/*
|
|
||||||
class GrainInput {
|
|
||||||
static inputs = [];
|
|
||||||
name;
|
|
||||||
unit;
|
|
||||||
mpg;
|
|
||||||
inputEl;
|
|
||||||
reference;
|
|
||||||
|
|
||||||
* @param {{
|
|
||||||
* name: string,
|
|
||||||
* mpg: number,
|
|
||||||
* reference: GrainInput | 'self',
|
|
||||||
* unit: string,
|
|
||||||
* step?: number,
|
|
||||||
* }} opts
|
|
||||||
constructor(opts) {
|
|
||||||
this.name = opts.name;
|
|
||||||
this.mpg = opts.mpg;
|
|
||||||
this.unit = opts.unit;
|
|
||||||
this.reference = opts.reference === "self" ? this : opts.reference;
|
|
||||||
this.inputEl = h("input", { type: "number", min: 0, step: opts.step ?? 1 });
|
|
||||||
eventBus.addListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
attachInput(insertionPoint) {
|
|
||||||
insertionPoint.appendChild(this.inputEl);
|
|
||||||
this.inputEl.valueAsNumber = this.mpg;
|
|
||||||
this.inputEl.addEventListener("input", (e) => {
|
|
||||||
const newVal = (e.currentTarget)?.valueAsNumber ?? 0;
|
|
||||||
if (this !== this.reference) {
|
|
||||||
this.reference.inputEl.valueAsNumber = newVal / this.mpg;
|
|
||||||
}
|
|
||||||
eventBus.sendChange(this);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onChange() {
|
|
||||||
if (!this.reference || this === this.reference) return;
|
|
||||||
this.inputEl.valueAsNumber = this.mpg * this.reference.inputEl.valueAsNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrentValue() {
|
|
||||||
return this.inputEl.valueAsNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RatiosController {
|
|
||||||
t3Ratio = h("input", { type: "number", min: 0, step: 1 });
|
|
||||||
t4Ratio = h("input", { type: "number", min: 0, step: 1 });
|
|
||||||
t3Syn = h("input", { type: "number", min: 0 });
|
|
||||||
t4Syn = h("input", { type: "number", min: 0 });
|
|
||||||
t3 = 1;
|
|
||||||
t4 = 4;
|
|
||||||
reference;
|
|
||||||
|
|
||||||
constructor(referenceInput) {
|
|
||||||
this.reference = referenceInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
attachInputs(inputs) {
|
|
||||||
inputs.t3Ratio.replaceWith(this.t3Ratio);
|
|
||||||
inputs.t4Ratio.replaceWith(this.t4Ratio);
|
|
||||||
inputs.t3Syn.replaceWith(this.t3Syn);
|
|
||||||
inputs.t4Syn.replaceWith(this.t4Syn);
|
|
||||||
|
|
||||||
this.t3Ratio.addEventListener("input", (e) => {
|
|
||||||
const newVal = (e.currentTarget)?.valueAsNumber ?? 0;
|
|
||||||
this.t3 = newVal;
|
|
||||||
this.onChange();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.t4Ratio.addEventListener("input", (e) => {
|
|
||||||
const newVal = (e.currentTarget)?.valueAsNumber ?? 0;
|
|
||||||
this.t4 = newVal;
|
|
||||||
this.onChange();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.t3Syn.addEventListener("input", (e) => {
|
|
||||||
const newVal = (e.currentTarget)?.valueAsNumber ?? 0;
|
|
||||||
this.reference.inputEl.valueAsNumber = newVal / MPG_T3_SYN + this.t4Syn.valueAsNumber / MPG_T4_SYN;
|
|
||||||
this.t3 = newVal;
|
|
||||||
this.t4 = this.t4Syn.valueAsNumber;
|
|
||||||
this.updateRatio();
|
|
||||||
this.updateSyn();
|
|
||||||
eventBus.sendChange(this);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.t4Syn.addEventListener("input", (e) => {
|
|
||||||
const newVal = (e.currentTarget)?.valueAsNumber ?? 0;
|
|
||||||
this.reference.inputEl.valueAsNumber = newVal / MPG_T4_SYN + this.t3Syn.valueAsNumber / MPG_T3_SYN;
|
|
||||||
this.t3 = this.t3Syn.valueAsNumber;
|
|
||||||
this.t4 = newVal;
|
|
||||||
this.updateRatio();
|
|
||||||
this.updateSyn();
|
|
||||||
eventBus.sendChange(this);
|
|
||||||
});
|
|
||||||
|
|
||||||
eventBus.addListener(this);
|
|
||||||
this.onChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
onChange() {
|
|
||||||
this.updateRatio();
|
|
||||||
this.updateSyn();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateRatio() {
|
|
||||||
this.t3Ratio.valueAsNumber = this.t3;
|
|
||||||
this.t4Ratio.valueAsNumber = this.t4;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateSyn() {
|
|
||||||
const total = this.t3 + this.t4;
|
|
||||||
const t3Proportion = this.t3 / total;
|
|
||||||
const t4Proportion = this.t4 / total;
|
|
||||||
const grainsSyn = t3Proportion / MPG_T3_SYN + t4Proportion / MPG_T4_SYN;
|
|
||||||
const multiplierSyn = this.reference.getCurrentValue() / grainsSyn;
|
|
||||||
this.t3Syn.valueAsNumber = t3Proportion * multiplierSyn;
|
|
||||||
this.t4Syn.valueAsNumber = t4Proportion * multiplierSyn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ThyroidConverter extends DJElement {
|
|
||||||
static styles = css``;
|
|
||||||
|
|
||||||
static template = html;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const mainGrainInput = new GrainInput({
|
|
||||||
name: "Grains",
|
|
||||||
mpg: 1,
|
|
||||||
reference: "self",
|
|
||||||
unit: "",
|
|
||||||
step: 0.1,
|
|
||||||
});
|
|
||||||
|
|
||||||
const ratiosController = new RatiosController(mainGrainInput);
|
|
||||||
|
|
||||||
const inputs = [
|
|
||||||
mainGrainInput,
|
|
||||||
new GrainInput({
|
|
||||||
name: "Armour, Natural Dessicated Thyroid",
|
|
||||||
mpg: 60,
|
|
||||||
unit: "mg",
|
|
||||||
reference: mainGrainInput,
|
|
||||||
}),
|
|
||||||
new GrainInput({
|
|
||||||
name: 'Liothyronine (Triiodothyronine, "Cytomel", T3)',
|
|
||||||
mpg: MPG_T3_SYN,
|
|
||||||
unit: "mcg",
|
|
||||||
reference: mainGrainInput,
|
|
||||||
}),
|
|
||||||
new GrainInput({
|
|
||||||
name: 'Levothyroxine (Thyroxine, "Cynoplus", T4)',
|
|
||||||
mpg: MPG_T4_SYN,
|
|
||||||
unit: "mcg",
|
|
||||||
reference: mainGrainInput,
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|
||||||
const tableBody = qs("#table-body", this.root);
|
|
||||||
const compoundedStart = qs("#compounded-start", this.root);
|
|
||||||
|
|
||||||
for (const field of inputs) {
|
|
||||||
const newRow = h("tr", {}, [
|
|
||||||
h("td", { textContent: field.name }),
|
|
||||||
h("td", {}, [
|
|
||||||
h("div", { className: "input", style: "display: inline-block;" }),
|
|
||||||
h("span", { className: "breathe", textContent: field.unit }),
|
|
||||||
]),
|
|
||||||
]);
|
|
||||||
field.attachInput(qs("div.input", newRow));
|
|
||||||
tableBody.insertBefore(newRow, compoundedStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
ratiosController.attachInputs({
|
|
||||||
t3Ratio: qs(".ratios .t3", tableBody),
|
|
||||||
t4Ratio: qs(".ratios .t4", tableBody),
|
|
||||||
t3Syn: qs(".synthetic .t3", tableBody),
|
|
||||||
t4Syn: qs(".synthetic .t4", tableBody),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ge-calculator',
|
name: "ge-calculator",
|
||||||
setup() {
|
setup() {
|
||||||
const t3Ratio = ref(1);
|
const t3Ratio = ref(1);
|
||||||
const t4Ratio = ref(4);
|
const t4Ratio = ref(4);
|
||||||
@@ -209,12 +22,12 @@ export default defineComponent({
|
|||||||
unit: "mg",
|
unit: "mg",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Liothyronine (Triiodothyronine, "Cytomel", T3)',
|
name: 'Liothyronine (Triiodothyronine, "Cytomel/Cynomel", T3)',
|
||||||
mpg: MPG_T3_SYN,
|
mpg: MPG_T3_SYN,
|
||||||
unit: "mcg",
|
unit: "mcg",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Levothyroxine (Thyroxine, "Cynoplus", T4)',
|
name: "Levothyroxine (Thyroxine, T4)",
|
||||||
mpg: MPG_T4_SYN,
|
mpg: MPG_T4_SYN,
|
||||||
unit: "mcg",
|
unit: "mcg",
|
||||||
},
|
},
|
||||||
@@ -222,7 +35,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
const numGrains = ref(2);
|
const numGrains = ref(2);
|
||||||
|
|
||||||
const ratio = computed(() => t3Ratio.value + t4Ratio.value);
|
|
||||||
const compounded = computed(() => {
|
const compounded = computed(() => {
|
||||||
const total = t3Ratio.value + t4Ratio.value;
|
const total = t3Ratio.value + t4Ratio.value;
|
||||||
const t3Proportion = t3Ratio.value / total;
|
const t3Proportion = t3Ratio.value / total;
|
||||||
@@ -235,7 +47,8 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => <>
|
return () => (
|
||||||
|
<>
|
||||||
<header>
|
<header>
|
||||||
<h1>Thyroid Calculator</h1>
|
<h1>Thyroid Calculator</h1>
|
||||||
</header>
|
</header>
|
||||||
@@ -244,14 +57,14 @@ export default defineComponent({
|
|||||||
Use this calculator to convert between different forms and units of thyroid hormone. Common
|
Use this calculator to convert between different forms and units of thyroid hormone. Common
|
||||||
synthetic, pure and natural dessicated forms are listed. The last section of the table provides
|
synthetic, pure and natural dessicated forms are listed. The last section of the table provides
|
||||||
input fields for a specified ratio of T3 to T4, and will give the dosages required for both the
|
input fields for a specified ratio of T3 to T4, and will give the dosages required for both the
|
||||||
synthetic and pure forms. All dosages given are based on the "Grains" field at the beginning of the
|
synthetic and pure forms. All dosages given are based on the "Grains" field at the beginning of
|
||||||
table, but editing any field will automatically update the rest to keep them in sync.
|
the table, but editing any field will automatically update the rest to keep them in sync.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-slab ge-calculator">
|
<div class="text-slab ge-calculator">
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
{ inputDefs.map((_, i) => (
|
{inputDefs.map((_) => (
|
||||||
<tr key={_.name}>
|
<tr key={_.name}>
|
||||||
<td>
|
<td>
|
||||||
{_.name}
|
{_.name}
|
||||||
@@ -259,10 +72,10 @@ export default defineComponent({
|
|||||||
<td class="right">
|
<td class="right">
|
||||||
<div style="display: inline-block;">
|
<div style="display: inline-block;">
|
||||||
<input
|
<input
|
||||||
value={_.name === 'Grains' ? numGrains.value : _.mpg * numGrains.value}
|
value={_.name === "Grains" ? numGrains.value : _.mpg * numGrains.value}
|
||||||
onInput={(e) => {
|
onInput={(e) => {
|
||||||
const val = (e.target as HTMLInputElement).valueAsNumber;
|
const val = (e.target as HTMLInputElement).valueAsNumber;
|
||||||
if (_.name === 'Grains') {
|
if (_.name === "Grains") {
|
||||||
numGrains.value = val;
|
numGrains.value = val;
|
||||||
} else {
|
} else {
|
||||||
numGrains.value = _.mpg / val;
|
numGrains.value = _.mpg / val;
|
||||||
@@ -270,13 +83,18 @@ export default defineComponent({
|
|||||||
}}
|
}}
|
||||||
min="0"
|
min="0"
|
||||||
step={_.step ?? 1}
|
step={_.step ?? 1}
|
||||||
type="number" />
|
type="number"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span class="breathe">{_.unit}</span>
|
<span class="breathe">{_.unit}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
<tr><td colspan="2"><strong>Compounded (T3 and T4, "Cynpolus")</strong></td></tr>
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<strong>Compounded (T3 and T4, "Cynoplus")</strong>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr class="ratios">
|
<tr class="ratios">
|
||||||
<td>
|
<td>
|
||||||
Desired Ratio (T3:T4)
|
Desired Ratio (T3:T4)
|
||||||
@@ -290,8 +108,11 @@ export default defineComponent({
|
|||||||
}}
|
}}
|
||||||
min="0"
|
min="0"
|
||||||
step="1"
|
step="1"
|
||||||
type="number" />
|
type="number"
|
||||||
</div> : <div>
|
/>
|
||||||
|
</div>{" "}
|
||||||
|
:{" "}
|
||||||
|
<div>
|
||||||
<input
|
<input
|
||||||
value={t4Ratio.value}
|
value={t4Ratio.value}
|
||||||
onInput={(e) => {
|
onInput={(e) => {
|
||||||
@@ -299,7 +120,8 @@ export default defineComponent({
|
|||||||
}}
|
}}
|
||||||
min="0"
|
min="0"
|
||||||
step="1"
|
step="1"
|
||||||
type="number" />
|
type="number"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -314,22 +136,28 @@ export default defineComponent({
|
|||||||
onInput={(e) => {
|
onInput={(e) => {
|
||||||
t4Ratio.value = compounded.value.t4Syn;
|
t4Ratio.value = compounded.value.t4Syn;
|
||||||
t3Ratio.value = (e.currentTarget as HTMLInputElement).valueAsNumber;
|
t3Ratio.value = (e.currentTarget as HTMLInputElement).valueAsNumber;
|
||||||
numGrains.value = t3Ratio.value / MPG_T3_SYN + t4Ratio.value / MPG_T4_SYN;
|
numGrains.value = t3Ratio.value / MPG_T3_SYN +
|
||||||
|
t4Ratio.value / MPG_T4_SYN;
|
||||||
}}
|
}}
|
||||||
min="0"
|
min="0"
|
||||||
step="1"
|
step="1"
|
||||||
type="number" />
|
type="number"
|
||||||
</div> : <div>
|
/>
|
||||||
|
</div>{" "}
|
||||||
|
:{" "}
|
||||||
|
<div>
|
||||||
<input
|
<input
|
||||||
value={compounded.value.t4Syn}
|
value={compounded.value.t4Syn}
|
||||||
onInput={(e) => {
|
onInput={(e) => {
|
||||||
t3Ratio.value = compounded.value.t3Syn;
|
t3Ratio.value = compounded.value.t3Syn;
|
||||||
t4Ratio.value = (e.currentTarget as HTMLInputElement).valueAsNumber;
|
t4Ratio.value = (e.currentTarget as HTMLInputElement).valueAsNumber;
|
||||||
numGrains.value = t3Ratio.value / MPG_T3_SYN + t4Ratio.value / MPG_T4_SYN;
|
numGrains.value = t3Ratio.value / MPG_T3_SYN +
|
||||||
|
t4Ratio.value / MPG_T4_SYN;
|
||||||
}}
|
}}
|
||||||
min="0"
|
min="0"
|
||||||
step="1"
|
step="1"
|
||||||
type="number" />
|
type="number"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -344,12 +172,13 @@ export default defineComponent({
|
|||||||
November 2024: Migrated to new web framework and fixed some buggy input.
|
November 2024: Migrated to new web framework and fixed some buggy input.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
13th March 2024: Removed the synthetic/pure distinction as it was confusing and unnecessary
|
13th March 2024: Removed the synthetic/pure distinction as it was confusing and
|
||||||
bloat.
|
unnecessary bloat.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</>;
|
</>
|
||||||
}
|
);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,23 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from "vue";
|
||||||
import { RouterLink } from 'vue-router';
|
import { RouterLink } from "vue-router";
|
||||||
import DJEmail from "@/DJEmail.tsx";
|
import DJEmail from "@/DJEmail.tsx";
|
||||||
|
import useHead from "@/useHead.ts";
|
||||||
|
import useAsyncState from "@/useAsyncState.ts";
|
||||||
|
import getDJAPI from "@/api.ts";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ge-deutsch',
|
name: "ge-deutsch",
|
||||||
setup() {
|
async setup() {
|
||||||
return () => <>
|
useHead({ title: "Ray Peat Artikel auf Deutsch" });
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: rpArticles,
|
||||||
|
stateIsReady,
|
||||||
|
} = useAsyncState("rp-articles", ({ hostUrl }) => getDJAPI(hostUrl, "/rp-articles"));
|
||||||
|
|
||||||
|
await stateIsReady;
|
||||||
|
return () => (
|
||||||
|
<>
|
||||||
<header>
|
<header>
|
||||||
<h1>Ray Peat Deutsche Übersetzungen</h1>
|
<h1>Ray Peat Deutsche Übersetzungen</h1>
|
||||||
</header>
|
</header>
|
||||||
@@ -16,46 +28,49 @@ export default defineComponent({
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Ray Peat war ein US-Amerikaner aus Eugene, Oregon, der neben seinem Studium von Linguistik,
|
Ray Peat war ein US-Amerikaner aus Eugene, Oregon, der neben seinem Studium von Linguistik,
|
||||||
Literatur, und Malerei eine Promotion in der Biologie und Physiologie des Alterns und degenerativer
|
Literatur, und Malerei eine Promotion in der Biologie und Physiologie des Alterns und
|
||||||
Krankheiten absolvierte, mit besonderem Fokus auf Zellen-Stoffwechsel, Hormone, und
|
degenerativer Krankheiten absolvierte, mit besonderem Fokus auf Zellen-Stoffwechsel, Hormone,
|
||||||
Ernährungsphysiologie.
|
und Ernährungsphysiologie.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Nach mehreren Jahren als Professor an diversen Universitäten in den USA und Mexiko begann er Artikel
|
Nach mehreren Jahren als Professor an diversen Universitäten in den USA und Mexiko begann er
|
||||||
in Form eines Newsletters herauszugeben, von denen mehrere auf <a href="http://raypeat.com/"
|
Artikel in Form eines Newsletters herauszugeben, von denen mehrere auf{" "}
|
||||||
>seiner Website</a> zu finden sind.
|
<a href="http://raypeat.com/">seiner Website</a> zu finden sind.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Da er in meinem Leben zu einem enormen Verständnis meines Körpers und einem unglaublichen
|
Da er in meinem Leben zu einem enormen Verständnis meines Körpers und einem unglaublichen
|
||||||
Zurückerlangen meiner Gesundheit und meines Wohlbefindens trotz dem Scheitern mehrerer Ärzte
|
Zurückerlangen meiner Gesundheit und meines Wohlbefindens trotz dem Scheitern mehrerer Ärzte
|
||||||
beigetragen hat, und sein Nachlass in Deutschland kaum Publikum aufgrund schwieriger physiologischer
|
beigetragen hat, und sein Nachlass in Deutschland kaum Publikum aufgrund schwieriger
|
||||||
Texte genießt, habe ich entschieden hauptsächlich für Freunde und Bekannte einige seiner Artikel ins
|
physiologischer Texte genießt, habe ich entschieden hauptsächlich für Freunde und Bekannte
|
||||||
Deutsche zu übersetzen, damit vielleicht auch ein breiteres Publikum von seinen Ideen profitieren
|
einige seiner Artikel ins Deutsche zu übersetzen, damit vielleicht auch ein breiteres Publikum
|
||||||
könnte.
|
von seinen Ideen profitieren könnte.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Falls was bei der Übersetzung auffällt oder besonders unidiomatisch klingt, bzw. der deutschen
|
Falls was bei der Übersetzung auffällt oder besonders unidiomatisch klingt, bzw. der deutschen
|
||||||
Fachsprache der Medizin nicht gerecht sein sollte, kannst du mir unter <DJEmail /> eine Mail senden.
|
Fachsprache der Medizin nicht gerecht sein sollte, kannst du mir unter <DJEmail />{" "}
|
||||||
Meine Muttersprache ist schließlich Englisch und ich bin kein professioneller Übersetzer!
|
eine Mail senden. Meine Muttersprache ist schließlich Englisch und ich bin kein professioneller
|
||||||
|
Übersetzer!
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Zusätzlich zu der Funktion, den Artikel mit dem Button oben in der Originalversion anzusehen, hat
|
Zusätzlich zu der Funktion, den Artikel mit dem Button oben in der Originalversion anzusehen,
|
||||||
jeder Absatz oben rechts beim drüberhovern mit der Maus einen zusätzlichen Button über den man den
|
hat jeder Absatz oben rechts beim drüberhovern mit der Maus einen zusätzlichen Button über den
|
||||||
jeweiligen Absatz in die andere Sprache wechseln kann, um die Versionen beim Lesen schnell zu
|
man den jeweiligen Absatz in die andere Sprache wechseln kann, um die Versionen beim Lesen
|
||||||
vergleichen zu können.
|
schnell zu vergleichen zu können.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-slab">
|
<div class="text-slab">
|
||||||
<h3>Artikel auswählen:</h3>
|
<h3>Artikel auswählen:</h3>
|
||||||
<ul id="article">
|
<ul id="article">
|
||||||
|
{rpArticles.value && rpArticles.value.map((_) => (
|
||||||
<li>
|
<li>
|
||||||
<RouterLink to={{ name: 'GEDeutschArticle', params: { articleName: 'hypothyroidism'}}}>Indikatoren Schilddrüsenunterfunktion</RouterLink>
|
<RouterLink to={{ name: "GEDeutschArticle", params: { articleName: _.slug } }}>
|
||||||
</li>
|
{_.name}
|
||||||
<li>
|
</RouterLink>
|
||||||
<RouterLink to={{ name: 'GEDeutschArticle', params: { articleName: 'caffeine'}}}>Koffein</RouterLink>
|
|
||||||
</li>
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</>;
|
</>
|
||||||
}
|
);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { h, inject, defineComponent, ref, createTextVNode, type VNode } from 'vue';
|
import { createTextVNode, defineComponent, h, inject, onServerPrefetch, ref, type VNode, watchEffect } from "vue";
|
||||||
import { RouterLink } from 'vue-router';
|
import { RouterLink } from "vue-router";
|
||||||
import useAsyncState from "@/useAsyncState.ts";
|
import useAsyncState from "@/useAsyncState.ts";
|
||||||
|
import useHead from "@/useHead.ts";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ge-deutsch-article',
|
name: "ge-deutsch-article",
|
||||||
props: {
|
props: {
|
||||||
articleName: {
|
articleName: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -17,24 +18,50 @@ export default defineComponent({
|
|||||||
currentLang.value = currentLang.value === "en" ? "de" : "en";
|
currentLang.value = currentLang.value === "en" ? "de" : "en";
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseDom = inject('dom-parse', (innerHTML: string) => Object.assign(document.createElement('div'), { innerHTML }));
|
const parseDom = inject(
|
||||||
|
"dom-parse",
|
||||||
|
(innerHTML: string) => Object.assign(document.createElement("div"), { innerHTML }),
|
||||||
|
);
|
||||||
|
|
||||||
const { result: articleContent, stateIsReady } = useAsyncState('ge-deutsch-article-data', async ({ hostUrl }) => {
|
const title = ref("");
|
||||||
const articleResponse = await fetch(`${ hostUrl }/generative-energy/static/content/${ props.articleName }.html`);
|
|
||||||
return await articleResponse.text();
|
const { result: articleContent, stateIsReady } = useAsyncState(
|
||||||
|
"ge-deutsch-article-data",
|
||||||
|
async ({ hostUrl }) => {
|
||||||
|
const articleResponse = await fetch(`${hostUrl}/generative-energy/content/${props.articleName}.html`);
|
||||||
|
const result = await articleResponse.text();
|
||||||
|
title.value = result.split('<h1 lang="de">')[1].split("</h1>")[0];
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
useHead({ title });
|
||||||
|
|
||||||
|
onServerPrefetch(() =>
|
||||||
|
new Promise<void>((res) => {
|
||||||
|
watchEffect(() => {
|
||||||
|
if (title.value !== "") {
|
||||||
|
console.log("resolve", title.value);
|
||||||
|
res();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
function transformArticleNode(node: Node): VNode | string {
|
function transformArticleNode(node: Node): VNode | string {
|
||||||
if (node.nodeType === node.ELEMENT_NODE) {
|
if (node.nodeType === node.ELEMENT_NODE) {
|
||||||
const el = node as Element;
|
const el = node as Element;
|
||||||
const attrs: Record<string, string> = {};
|
const attrs: Record<string, string> = {};
|
||||||
const children = [...node.childNodes].map(_ => transformArticleNode(_));
|
const children = [...node.childNodes].map((_) => transformArticleNode(_));
|
||||||
|
|
||||||
if (el.tagName === 'P') {
|
if (el.tagName === "P") {
|
||||||
el.classList.add('text-slab');
|
el.classList.add("text-slab");
|
||||||
children.unshift(h('button', { class: 'swap', onClick: (e) => {
|
children.unshift(h("button", {
|
||||||
e.target.parentElement.classList.toggle('swap');
|
class: "swap",
|
||||||
} }, '↻'));
|
onClick: (e) => {
|
||||||
|
e.target.parentElement.classList.toggle("swap");
|
||||||
|
},
|
||||||
|
}, "↻"));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < el.attributes.length; i++) {
|
for (let i = 0; i < el.attributes.length; i++) {
|
||||||
@@ -46,23 +73,24 @@ export default defineComponent({
|
|||||||
|
|
||||||
return h((node as Element).tagName, attrs, children);
|
return h((node as Element).tagName, attrs, children);
|
||||||
} else {
|
} else {
|
||||||
return createTextVNode(node.textContent ?? '');
|
return createTextVNode(node.textContent ?? "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ArticleContentTransformed() {
|
function ArticleContentTransformed() {
|
||||||
if (articleContent.value) {
|
if (articleContent.value) {
|
||||||
const dom = parseDom(articleContent.value);
|
const dom = parseDom(articleContent.value);
|
||||||
return h('div', {}, [...dom.children].map(_ => transformArticleNode(_)));
|
return h("div", {}, [...dom.children].map((_) => transformArticleNode(_)));
|
||||||
}
|
}
|
||||||
return <div>Artikel lädt...</div>;
|
return <div>Artikel lädt...</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
await stateIsReady;
|
await stateIsReady;
|
||||||
|
|
||||||
return () => <div class="ge-article">
|
return () => (
|
||||||
|
<div class="ge-article">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<RouterLink to={{ name: 'GEDeutsch' }}>Zur Artikelübersicht</RouterLink>
|
<RouterLink to={{ name: "GEDeutsch" }}>Zur Artikelübersicht</RouterLink>
|
||||||
<button onClick={clickBtn}>
|
<button onClick={clickBtn}>
|
||||||
Sprache auf <span>{currentLang.value === "en" ? "Deutsch" : "Englisch"}</span> umschalten
|
Sprache auf <span>{currentLang.value === "en" ? "Deutsch" : "Englisch"}</span> umschalten
|
||||||
</button>
|
</button>
|
||||||
@@ -70,6 +98,7 @@ export default defineComponent({
|
|||||||
<article class={`lang-${currentLang.value}`}>
|
<article class={`lang-${currentLang.value}`}>
|
||||||
<ArticleContentTransformed />
|
<ArticleContentTransformed />
|
||||||
</article>
|
</article>
|
||||||
</div>;
|
</div>
|
||||||
}
|
);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,27 +1,32 @@
|
|||||||
import { RouterLink } from 'vue-router';
|
import { RouterLink } from "vue-router";
|
||||||
|
import useHead from "@/useHead.ts";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ge-main',
|
name: "ge-main",
|
||||||
setup() {
|
setup() {
|
||||||
return () => <>
|
useHead({ title: "Generative Energy" });
|
||||||
|
return () => (
|
||||||
|
<>
|
||||||
<header>
|
<header>
|
||||||
<h1>Generative Energy</h1>
|
<h1>Generative Energy</h1>
|
||||||
</header>
|
</header>
|
||||||
<div class="text-slab">
|
<div class="text-slab">
|
||||||
<p>
|
<p>
|
||||||
This page is dedicated to Dr. Raymond Peat († 2022), who has had a profound impact on my health and
|
This page is dedicated to Dr. Raymond Peat († 2022), who has had a profound impact on my health
|
||||||
my life in general. Hover over the links below for more detail.
|
and my life in general. Hover over the links below for more detail.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-slab">
|
<div class="text-slab">
|
||||||
<h2>Links</h2>
|
<h2>Links</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<RouterLink to={{ name: 'GECalculator' }}>Thyroid Calculator</RouterLink>
|
<RouterLink to={{ name: "GECalculator" }}>Thyroid Calculator</RouterLink>
|
||||||
<span style="display: none" class="tooltip">Convert to and from grains, set ratios, etc.</span>
|
<span style="display: none" class="tooltip">
|
||||||
|
Convert to and from grains, set ratios, etc.
|
||||||
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<RouterLink to={{ name: 'GEDeutsch' }}>Ray Peat Articles in German</RouterLink>
|
<RouterLink to={{ name: "GEDeutsch" }}>Ray Peat Articles in German</RouterLink>
|
||||||
<span style="display: none" class="tooltip">
|
<span style="display: none" class="tooltip">
|
||||||
A selection of articles by Ray that I have translated in my spare time into German.
|
A selection of articles by Ray that I have translated in my spare time into German.
|
||||||
</span>
|
</span>
|
||||||
@@ -29,5 +34,6 @@ export default {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import { defineComponent } from "vue";
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "dj-paypal-donate",
|
|
||||||
setup: () => {
|
|
||||||
return () => (
|
|
||||||
<form action="https://www.paypal.com/donate" method="post" target="_top">
|
|
||||||
<input type="hidden" name="hosted_button_id" value="9NXC6V5HDPGFL" />
|
|
||||||
<input
|
|
||||||
id="ppbutton"
|
|
||||||
type="image"
|
|
||||||
src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif"
|
|
||||||
name="submit"
|
|
||||||
title="Thanks for your support!"
|
|
||||||
alt="Donate with PayPal button"
|
|
||||||
/>
|
|
||||||
<img alt="" src="https://www.paypal.com/en_DE/i/scr/pixel.gif" width="1" height="1" />
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,34 +1,34 @@
|
|||||||
import { defineComponent, type VNode, Suspense } from "vue";
|
import { defineComponent, Suspense, type VNode } from "vue";
|
||||||
import { useRoute, RouterLink, RouterView, type RouteRecordRaw } from 'vue-router';
|
import { type RouteRecordRaw, RouterLink, RouterView, useRoute } from "vue-router";
|
||||||
import GEMain from "@/generative-energy/GEMain.tsx";
|
import GEMain from "@/generative-energy/GEMain.tsx";
|
||||||
import DJEmail from "@/DJEmail.tsx";
|
import DJEmail from "@/DJEmail.tsx";
|
||||||
import GEPaypal from "@/generative-energy/GEPaypal.tsx";
|
|
||||||
import GEDeutsch from "@/generative-energy/GEDeutsch.tsx";
|
import GEDeutsch from "@/generative-energy/GEDeutsch.tsx";
|
||||||
import GEDeutschArticle from "@/generative-energy/GEDeutschArticle.tsx";
|
import GEDeutschArticle from "@/generative-energy/GEDeutschArticle.tsx";
|
||||||
import GECalculator from "@/generative-energy/GECalculator.tsx";
|
import GECalculator from "@/generative-energy/GECalculator.tsx";
|
||||||
|
import DJDonate from "@/DJDonate.tsx";
|
||||||
|
|
||||||
export const routes: RouteRecordRaw[] = [
|
export const routes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: "/",
|
||||||
name: 'GEMain',
|
name: "GEMain",
|
||||||
component: GEMain,
|
component: GEMain,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/calculator',
|
path: "/calculator",
|
||||||
name: 'GECalculator',
|
name: "GECalculator",
|
||||||
component: GECalculator,
|
component: GECalculator,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/raypeat-deutsch',
|
path: "/raypeat-deutsch",
|
||||||
name: 'GEDeutsch',
|
name: "GEDeutsch",
|
||||||
component: GEDeutsch,
|
component: GEDeutsch,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/raypeat-deutsch/article/:articleName',
|
path: "/raypeat-deutsch/article/:articleName",
|
||||||
name: 'GEDeutschArticle',
|
name: "GEDeutschArticle",
|
||||||
component: GEDeutschArticle,
|
component: GEDeutschArticle,
|
||||||
props: ({ params }) => {
|
props: ({ params }) => {
|
||||||
if ('articleName' in params) {
|
if ("articleName" in params) {
|
||||||
return { articleName: params.articleName };
|
return { articleName: params.articleName };
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@@ -41,27 +41,35 @@ export default defineComponent({
|
|||||||
name: "ge-root",
|
name: "ge-root",
|
||||||
setup() {
|
setup() {
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
return () => <>
|
return () => (
|
||||||
|
<>
|
||||||
<main>
|
<main>
|
||||||
<RouterLink class={"home-btn" + (route.name === 'GEMain' ? ' hide' : '') }
|
<RouterLink class={"home-btn" + (route.name === "GEMain" ? " hide" : "")} to={{ name: "GEMain" }}>
|
||||||
to={{ name: 'GEMain' }}>
|
|
||||||
Generative Energy Home
|
Generative Energy Home
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
<RouterView>{{ default: ({ Component }: { Component: VNode }) => (Component &&
|
<RouterView>
|
||||||
<Suspense>{{
|
{{
|
||||||
|
default: ({ Component }: { Component: VNode }) => (Component &&
|
||||||
|
(
|
||||||
|
<Suspense>
|
||||||
|
{{
|
||||||
default: () => Component,
|
default: () => Component,
|
||||||
fallback: () => <div>Page loading...</div>,
|
fallback: () => <div>Page loading...</div>,
|
||||||
}}</Suspense>
|
}}
|
||||||
)}}</RouterView>
|
</Suspense>
|
||||||
|
)),
|
||||||
|
}}
|
||||||
|
</RouterView>
|
||||||
<footer>
|
<footer>
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<div>
|
<div>
|
||||||
<a href="https://djledda.de/">djledda.de</a> 2023 - <DJEmail>{ () => 'Contact' }</DJEmail>
|
<a href="/">djledda.de</a> 2023 - <DJEmail>{() => "Contact"}</DJEmail>
|
||||||
</div>
|
</div>
|
||||||
<GEPaypal />
|
<DJDonate />
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</main>
|
</main>
|
||||||
</>;
|
</>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ import GERoot, { routes } from "@/generative-energy/GERoot.tsx";
|
|||||||
createSSRApp(GERoot)
|
createSSRApp(GERoot)
|
||||||
.use(createRouter({
|
.use(createRouter({
|
||||||
routes,
|
routes,
|
||||||
history: createWebHistory('/generative-energy')
|
history: createWebHistory("/generative-energy"),
|
||||||
}))
|
}))
|
||||||
.mount('#app-root');
|
.mount("#app-root");
|
||||||
|
|||||||
12
app/generative-energy/server.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { createSSRApp } from "vue";
|
||||||
|
import { createMemoryHistory, createRouter } from "vue-router";
|
||||||
|
import GERoot, { routes } from "@/generative-energy/GERoot.tsx";
|
||||||
|
|
||||||
|
export default function createApp() {
|
||||||
|
const router = createRouter({
|
||||||
|
routes,
|
||||||
|
history: createMemoryHistory("/generative-energy"),
|
||||||
|
});
|
||||||
|
const app = createSSRApp(GERoot).use(router);
|
||||||
|
return { app, router };
|
||||||
|
}
|
||||||
@@ -1,19 +1,75 @@
|
|||||||
import { computed, defineComponent, ref } from "vue";
|
import { defineComponent } from "vue";
|
||||||
|
import useHead from "@/useHead.ts";
|
||||||
|
import DJTooltip from "@/DJTooltip.tsx";
|
||||||
|
import DJEmail from "@/DJEmail.tsx";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "app-root",
|
name: "app-root",
|
||||||
setup() {
|
setup() {
|
||||||
const count = ref(0);
|
useHead({ title: "DJ Ledda's Homepage" });
|
||||||
const countDouble = computed(() => count.value * 2);
|
|
||||||
count.value++;
|
|
||||||
return () => (
|
return () => (
|
||||||
<div class="app-main">
|
<div class="supercontainer">
|
||||||
<button class="test" onClick={() => count.value++}>Click me!</button>
|
<div class="shakeable">
|
||||||
<div>Count: {count.value}</div>
|
<div class="title_name">
|
||||||
<div>Count Double: {countDouble.value}</div>
|
<DJTooltip tooltip="I wonder what he's listening to?">
|
||||||
<p>
|
<img src="/home/img/dj.gif" alt="dj legt krasse Mucke auf" class="dude" />
|
||||||
<a href="/generative-energy/">Go to this other site hosted here but a different Vue app!</a>
|
</DJTooltip>
|
||||||
</p>
|
<DJTooltip tooltip="Easily the coolest guy out there.">
|
||||||
|
<span>DJ Ledda</span>
|
||||||
|
</DJTooltip>
|
||||||
|
<DJTooltip tooltip="I once heard this guy played at revs.">
|
||||||
|
<img src="/home/img/dj.gif" alt="dj laying down some sick beats" class="dude" />
|
||||||
|
</DJTooltip>
|
||||||
|
</div>
|
||||||
|
<div class="main">
|
||||||
|
<div class="subject">
|
||||||
|
<div class="resourcelist">
|
||||||
|
<a href="https://drum-slayer.com">
|
||||||
|
<DJTooltip class="resource" tooltip="Small app for designing multitrack looped rhythms with local save and multiple files. Originally built using just vanilla TypeScript and CSS, now with Vue.">
|
||||||
|
Drum Slayer
|
||||||
|
</DJTooltip>
|
||||||
|
</a>
|
||||||
|
<a href="/somaesque">
|
||||||
|
<DJTooltip class="resource" tooltip="Puzzle solver app for puzzle cubes resembling the original Soma Cube puzzle. Save and edit your own puzzles! Built with Svelte, THREE.js and AssemblyScript.">
|
||||||
|
Somaesque
|
||||||
|
</DJTooltip>
|
||||||
|
</a>
|
||||||
|
<a href="/generative-energy">
|
||||||
|
<DJTooltip class="resource" tooltip="Thyroid calculator, German translations, and more...">
|
||||||
|
Generative Energy - Ray Peat Resources
|
||||||
|
</DJTooltip>
|
||||||
|
</a>
|
||||||
|
<a href="/home/muenchen-auf-englisch.html">
|
||||||
|
<DJTooltip class="resource" tooltip="
|
||||||
|
Authentic historically accurate translations of all of Munich's S-Bahn and U-Bahn
|
||||||
|
stations, as well as the main municipalities, into English. You live in Allach? It's
|
||||||
|
Axleigh now. Giesing? Nope! Kyesing! This is a WIP.
|
||||||
|
">
|
||||||
|
München auf Englisch - Munich in English
|
||||||
|
</DJTooltip>
|
||||||
|
</a>
|
||||||
|
<a href="/kadi/">
|
||||||
|
<DJTooltip class="resource" tooltip="Make an account and start saving paper and tracking your Yatzy stats with your
|
||||||
|
friends! Make your own rulesets, and more. Built with React, express.js, and
|
||||||
|
MongoDB. Currently inactive.">
|
||||||
|
K A D I: Online Yatzy Scoresheets
|
||||||
|
</DJTooltip>
|
||||||
|
</a>
|
||||||
|
<a href="http://git.djledda.de/Ledda">
|
||||||
|
<DJTooltip class="resource" tooltip="Check out what I'm coding!">
|
||||||
|
My git projects
|
||||||
|
</DJTooltip>
|
||||||
|
</a>
|
||||||
|
<DJEmail>
|
||||||
|
<DJTooltip class="resource" tooltip="You'll see my address when you click here.">
|
||||||
|
Click here to get in touch
|
||||||
|
</DJTooltip>
|
||||||
|
</DJEmail>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="tooltipCarrier"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
4
app/home/client.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { createSSRApp } from "vue";
|
||||||
|
import App from "@/home/App.tsx";
|
||||||
|
|
||||||
|
createSSRApp(App).mount("#app-root");
|
||||||
7
app/home/server.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { createSSRApp } from "vue";
|
||||||
|
import App from "@/home/App.tsx";
|
||||||
|
|
||||||
|
export default function createApp() {
|
||||||
|
const app = createSSRApp(App);
|
||||||
|
return { app, router: null };
|
||||||
|
}
|
||||||
13
app/meta.ts
@@ -1,13 +0,0 @@
|
|||||||
import { useSSRContext, toValue, type MaybeRefOrGetter } from 'vue';
|
|
||||||
|
|
||||||
export default function useHead(params: {
|
|
||||||
title: MaybeRefOrGetter<string>,
|
|
||||||
}) {
|
|
||||||
const context = useSSRContext();
|
|
||||||
if (context) {
|
|
||||||
context.meta ??= {
|
|
||||||
title: toValue(params.title),
|
|
||||||
meta: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
122
app/tooltip.tsx
@@ -1,122 +0,0 @@
|
|||||||
import { h, qsa } from "@/util.ts";
|
|
||||||
import { type CSSProperties, defineComponent, onBeforeUnmount, onMounted, ref } from "vue";
|
|
||||||
|
|
||||||
const carrierStyle = {
|
|
||||||
opacity: "0",
|
|
||||||
display: "block",
|
|
||||||
pointerEvents: "none",
|
|
||||||
backgroundColor: "black",
|
|
||||||
border: "white solid 1px",
|
|
||||||
color: "white",
|
|
||||||
padding: "10px",
|
|
||||||
position: "absolute",
|
|
||||||
zIndex: "1",
|
|
||||||
overflow: "hidden",
|
|
||||||
height: "0",
|
|
||||||
width: "0",
|
|
||||||
transition: "opacity 200ms, height 200ms, width 200ms",
|
|
||||||
} satisfies CSSProperties;
|
|
||||||
|
|
||||||
const textCarrierStyle = {
|
|
||||||
width: "350px",
|
|
||||||
display: "block",
|
|
||||||
overflow: "hidden",
|
|
||||||
} satisfies CSSProperties;
|
|
||||||
|
|
||||||
const defaultWidth = 350;
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "dj-sexy-tooltip",
|
|
||||||
setup() {
|
|
||||||
const active = ref(false);
|
|
||||||
|
|
||||||
const carrier = ref<HTMLElement | null>(null);
|
|
||||||
const textCarrier = ref<HTMLElement | null>(null);
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
document.body.appendChild(h("style", { textContent: `.tooltip { display: none; }` }));
|
|
||||||
document.body.style.position = "relative";
|
|
||||||
|
|
||||||
document.addEventListener("mousemove", (event) => this.rerenderTooltip({ x: event.pageX, y: event.pageY }));
|
|
||||||
});
|
|
||||||
|
|
||||||
function rerenderTooltip(mousePos: { x: number; y: number }) {
|
|
||||||
const newText = this.getTooltipTextForHoveredElement(mousePos);
|
|
||||||
if (newText !== this.textCarrier) {
|
|
||||||
this.transitionTooltipSize(newText);
|
|
||||||
const tooltipHasText = newText !== "";
|
|
||||||
if (tooltipHasText !== this.active) {
|
|
||||||
this.toggleActive();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.isStillVisible()) {
|
|
||||||
this.updatePosition(mousePos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isStillVisible() {
|
|
||||||
return getComputedStyle(carrier.value).opacity !== "0";
|
|
||||||
}
|
|
||||||
|
|
||||||
function updatePosition(pos: { x: number; y: number }) {
|
|
||||||
if (pos.x + 15 + this.carrier.clientWidth <= document.body.scrollWidth) {
|
|
||||||
this.carrier.style.left = (pos.x + 15) + "px";
|
|
||||||
} else {
|
|
||||||
this.carrier.style.left = (document.body.scrollWidth - this.carrier.clientWidth - 5) + "px";
|
|
||||||
}
|
|
||||||
if (pos.y + this.carrier.clientHeight <= document.body.scrollHeight) {
|
|
||||||
this.carrier.style.top = pos.y + "px";
|
|
||||||
} else {
|
|
||||||
this.carrier.style.top = (document.body.scrollHeight - this.carrier.clientHeight - 5) + "px";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleActive() {
|
|
||||||
if (this.active) {
|
|
||||||
this.active = false;
|
|
||||||
this.carrier.style.opacity = "0";
|
|
||||||
this.carrier.style.padding = "0";
|
|
||||||
} else {
|
|
||||||
this.active = true;
|
|
||||||
this.carrier.style.opacity = "1";
|
|
||||||
this.carrier.style.padding = SexyTooltip.carrierStyle.padding;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function transitionTooltipSize(text: string) {
|
|
||||||
const testDiv = h("div");
|
|
||||||
testDiv.style.height = "auto";
|
|
||||||
testDiv.style.width = SexyTooltip.defaultWidth + "px";
|
|
||||||
testDiv.innerHTML = text;
|
|
||||||
document.body.appendChild(testDiv);
|
|
||||||
const calculatedHeight = testDiv.scrollHeight;
|
|
||||||
testDiv.style.display = "inline";
|
|
||||||
testDiv.style.width = "auto";
|
|
||||||
document.body.removeChild(testDiv);
|
|
||||||
const size = { height: calculatedHeight + "px", width: "350px" };
|
|
||||||
this.carrier.style.height = size.height;
|
|
||||||
this.carrier.style.width = text === "" ? "0" : size.width;
|
|
||||||
this.textCarrier.innerHTML = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTooltipTextForHoveredElement(mousePos: { x: number; y: number }) {
|
|
||||||
for (const elem of this.elementsWithTooltips) {
|
|
||||||
const boundingRect = elem.getBoundingClientRect();
|
|
||||||
const inYRange = mousePos.y >= boundingRect.top + window.pageYOffset - 1 &&
|
|
||||||
mousePos.y <= boundingRect.bottom + window.pageYOffset + 1;
|
|
||||||
const inXRange = mousePos.x >= boundingRect.left + window.pageXOffset - 1 &&
|
|
||||||
mousePos.x <= boundingRect.right + window.pageXOffset + 1;
|
|
||||||
if (inYRange && inXRange) {
|
|
||||||
return elem.nextElementSibling?.innerText ?? "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => (
|
|
||||||
<div ref={carrier}>
|
|
||||||
<span ref={textCarrier} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,17 +1,22 @@
|
|||||||
import { onMounted, onServerPrefetch, useSSRContext, shallowRef, type ShallowRef } from 'vue';
|
import { onMounted, onServerPrefetch, type ShallowRef, shallowRef } from "vue";
|
||||||
|
import useDJSSRContext from "@/useDJSSRContext.ts";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// deno-lint-ignore no-var
|
// deno-lint-ignore no-var
|
||||||
var appstate: Partial<Record<string, unknown>>;
|
var appstate: Partial<Record<string, unknown>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function useAsyncState<T>(key: string, getter: (context: { hostUrl: string }) => Promise<T | null>, options?: { suspensible: boolean }): { result: ShallowRef<T | null>, stateIsReady: Promise<unknown> } {
|
export default function useAsyncState<T>(
|
||||||
const ssrContext = useSSRContext<{ registry: Record<string, unknown> }>();
|
key: string,
|
||||||
const isClient = typeof ssrContext === 'undefined';
|
getter: (context: { hostUrl: string }) => Promise<T | null>,
|
||||||
|
options?: { suspensible: boolean },
|
||||||
|
): { result: ShallowRef<T | null>; stateIsReady: Promise<unknown> } {
|
||||||
|
const ssrContext = useDJSSRContext();
|
||||||
|
const isClient = typeof ssrContext === "undefined";
|
||||||
|
|
||||||
const registry = ssrContext?.registry ?? globalThis?.appstate;
|
const registry = ssrContext?.registry ?? globalThis?.appstate;
|
||||||
|
|
||||||
const hostUrl = isClient ? globalThis.location.origin : 'http://localhost:8080';
|
const hostUrl = isClient ? globalThis.location.origin : "http://localhost:8080";
|
||||||
|
|
||||||
const state = shallowRef<T | null>(null);
|
const state = shallowRef<T | null>(null);
|
||||||
|
|
||||||
|
|||||||
12
app/useDJSSRContext.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { type MaybeRefOrGetter, useSSRContext } from "vue";
|
||||||
|
|
||||||
|
export type DJSSRContext = {
|
||||||
|
head: {
|
||||||
|
title: MaybeRefOrGetter<string>;
|
||||||
|
};
|
||||||
|
registry: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function useDJSSRContext() {
|
||||||
|
return useSSRContext<DJSSRContext>();
|
||||||
|
}
|
||||||
19
app/useHead.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { watchEffect, toValue, type MaybeRefOrGetter } from 'vue';
|
||||||
|
import useDJSSRContext from "@/useDJSSRContext.ts";
|
||||||
|
|
||||||
|
export default function useHead(params: {
|
||||||
|
title: MaybeRefOrGetter<string>,
|
||||||
|
}) {
|
||||||
|
const context = useDJSSRContext();
|
||||||
|
|
||||||
|
if (context) {
|
||||||
|
context.head.title = params.title;
|
||||||
|
} else {
|
||||||
|
watchEffect(() => {
|
||||||
|
const newTitle = toValue(params.title);
|
||||||
|
if (newTitle) {
|
||||||
|
document.title = newTitle;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
10
deno.lock
generated
@@ -11,11 +11,13 @@
|
|||||||
"jsr:@std/encoding@^1.0.5": "1.0.5",
|
"jsr:@std/encoding@^1.0.5": "1.0.5",
|
||||||
"jsr:@std/fmt@0.223": "0.223.0",
|
"jsr:@std/fmt@0.223": "0.223.0",
|
||||||
"jsr:@std/fmt@^1.0.3": "1.0.3",
|
"jsr:@std/fmt@^1.0.3": "1.0.3",
|
||||||
|
"jsr:@std/fs@*": "0.223.0",
|
||||||
"jsr:@std/fs@0.223": "0.223.0",
|
"jsr:@std/fs@0.223": "0.223.0",
|
||||||
"jsr:@std/http@*": "1.0.9",
|
"jsr:@std/http@*": "1.0.9",
|
||||||
"jsr:@std/io@0.223": "0.223.0",
|
"jsr:@std/io@0.223": "0.223.0",
|
||||||
"jsr:@std/media-types@^1.0.3": "1.0.3",
|
"jsr:@std/media-types@^1.0.3": "1.0.3",
|
||||||
"jsr:@std/net@^1.0.4": "1.0.4",
|
"jsr:@std/net@^1.0.4": "1.0.4",
|
||||||
|
"jsr:@std/path@*": "1.0.7",
|
||||||
"jsr:@std/path@0.223": "0.223.0",
|
"jsr:@std/path@0.223": "0.223.0",
|
||||||
"jsr:@std/path@^1.0.7": "1.0.7",
|
"jsr:@std/path@^1.0.7": "1.0.7",
|
||||||
"jsr:@std/streams@^1.0.7": "1.0.7",
|
"jsr:@std/streams@^1.0.7": "1.0.7",
|
||||||
@@ -34,7 +36,7 @@
|
|||||||
"dependencies": [
|
"dependencies": [
|
||||||
"jsr:@deno/graph",
|
"jsr:@deno/graph",
|
||||||
"jsr:@std/fmt@0.223",
|
"jsr:@std/fmt@0.223",
|
||||||
"jsr:@std/fs",
|
"jsr:@std/fs@0.223",
|
||||||
"jsr:@std/io",
|
"jsr:@std/io",
|
||||||
"jsr:@std/path@0.223"
|
"jsr:@std/path@0.223"
|
||||||
]
|
]
|
||||||
@@ -68,7 +70,11 @@
|
|||||||
"integrity": "97765c16aa32245ff4e2204ecf7d8562496a3cb8592340a80e7e554e0bb9149f"
|
"integrity": "97765c16aa32245ff4e2204ecf7d8562496a3cb8592340a80e7e554e0bb9149f"
|
||||||
},
|
},
|
||||||
"@std/fs@0.223.0": {
|
"@std/fs@0.223.0": {
|
||||||
"integrity": "3b4b0550b2c524cbaaa5a9170c90e96cbb7354e837ad1bdaf15fc9df1ae9c31c"
|
"integrity": "3b4b0550b2c524cbaaa5a9170c90e96cbb7354e837ad1bdaf15fc9df1ae9c31c",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@std/assert",
|
||||||
|
"jsr:@std/path@0.223"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"@std/http@1.0.9": {
|
"@std/http@1.0.9": {
|
||||||
"integrity": "d409fc319a5e8d4a154e576c758752e9700282d74f31357a12fec6420f9ecb6c",
|
"integrity": "d409fc319a5e8d4a154e576c758752e9700282d74f31357a12fec6420f9ecb6c",
|
||||||
|
|||||||
4
deps.ts
@@ -1,4 +1,6 @@
|
|||||||
import "jsr:@deno/emit";
|
import "jsr:@deno/emit";
|
||||||
import "jsr:@std/http";
|
import "jsr:@std/http";
|
||||||
import "vue";
|
import "vue";
|
||||||
import 'jsr:@b-fuze/deno-dom';
|
import "jsr:@b-fuze/deno-dom";
|
||||||
|
import "jsr:@std/fs";
|
||||||
|
import "jsr:@std/path";
|
||||||
|
|||||||
196
main.ts
@@ -1,56 +1,20 @@
|
|||||||
import { serveFile } from "jsr:@std/http/file-server";
|
import { serveFile } from "jsr:@std/http/file-server";
|
||||||
import { createSSRApp } from "vue";
|
import { type App, toValue } from "vue";
|
||||||
|
import { type Router } from "vue-router";
|
||||||
import { renderToString } from "vue/server-renderer";
|
import { renderToString } from "vue/server-renderer";
|
||||||
import { createRouter, createMemoryHistory } from 'vue-router';
|
|
||||||
import Home from "@/home/App.tsx";
|
|
||||||
import GERoot, { routes as geRoutes } from "@/generative-energy/GERoot.tsx";
|
|
||||||
import transpileResponse from "./transpile.ts";
|
import transpileResponse from "./transpile.ts";
|
||||||
import { DOMParser } from 'jsr:@b-fuze/deno-dom'
|
import { DOMParser } from "jsr:@b-fuze/deno-dom";
|
||||||
|
import { join } from "jsr:@std/path/join";
|
||||||
|
import { exists } from "jsr:@std/fs";
|
||||||
|
import { type DJSSRContext } from "@/useDJSSRContext.ts";
|
||||||
|
import { type DJAPIResult, type DJAPIResultMap } from "@/api.ts";
|
||||||
|
|
||||||
const utf8Decoder = new TextDecoder("utf-8");
|
const utf8Decoder = new TextDecoder("utf-8");
|
||||||
|
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
|
|
||||||
Deno.serve({
|
function appHeaderScript(params: { appstate: Record<string, unknown>; entryPath: string }) {
|
||||||
port: 8080,
|
return `<script type="importmap">
|
||||||
hostname: "0.0.0.0",
|
|
||||||
onListen({ port, hostname }) {
|
|
||||||
console.log(`Listening on port http://${hostname}:${port}/`);
|
|
||||||
},
|
|
||||||
}, async (req, _conn) => {
|
|
||||||
if (req.method === "GET") {
|
|
||||||
const pathname = URL.parse(req.url)?.pathname ?? "/";
|
|
||||||
if (pathname.startsWith('/static/') ||
|
|
||||||
pathname.startsWith('/generative-energy/static/')) {
|
|
||||||
if (pathname.startsWith('/static/')) {
|
|
||||||
return serveFile(req, `public/home/${ pathname }`);
|
|
||||||
} else {
|
|
||||||
return serveFile(req, `public${pathname}`);
|
|
||||||
}
|
|
||||||
} else if (pathname === "/") {
|
|
||||||
const rendered = await renderToString(createSSRApp(Home));
|
|
||||||
const content = utf8Decoder.decode(await Deno.readFile("./public/home/index.html"))
|
|
||||||
.replace(`<!-- SSR OUTLET -->`, rendered)
|
|
||||||
.replace(`<!-- SSR HEAD OUTLET -->`, "");
|
|
||||||
return new Response(content, { headers: { "Content-Type": "text/html" } });
|
|
||||||
} else if (pathname.startsWith('/generative-energy')) {
|
|
||||||
const app = createSSRApp(GERoot);
|
|
||||||
const router = createRouter({
|
|
||||||
routes: geRoutes,
|
|
||||||
history: createMemoryHistory('/generative-energy'),
|
|
||||||
});
|
|
||||||
app.use(router);
|
|
||||||
app.provide('dom-parse', (innerHTML: string) => {
|
|
||||||
return parser.parseFromString(innerHTML, 'text/html').documentElement;
|
|
||||||
});
|
|
||||||
const ssrContext = { registry: {}};
|
|
||||||
await router.replace(pathname.split('/generative-energy')[1]);
|
|
||||||
await router.isReady();
|
|
||||||
const rendered = await renderToString(app, ssrContext);
|
|
||||||
const content = utf8Decoder.decode(await Deno.readFile("./public/generative-energy/index.html"))
|
|
||||||
.replace('%TITLE%', 'Generative Energy')
|
|
||||||
.replace('<!-- SSR HEAD OUTLET -->', `
|
|
||||||
<script type="importmap">
|
|
||||||
{
|
{
|
||||||
"imports": {
|
"imports": {
|
||||||
"vue": "/deps/vue/dist/vue.esm-browser.prod.js",
|
"vue": "/deps/vue/dist/vue.esm-browser.prod.js",
|
||||||
@@ -61,20 +25,140 @@ Deno.serve({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script> window.appstate = ${ JSON.stringify(ssrContext.registry) }; </script>
|
<script type="module">
|
||||||
`)
|
window.appstate = ${JSON.stringify(params.appstate)};
|
||||||
.replace(`<!-- SSR OUTLET -->`, rendered);
|
import('${params.entryPath}');
|
||||||
return new Response(content, { headers: { "Content-Type": "text/html" } });
|
</script>`;
|
||||||
} else if (pathname.startsWith("/app") && (pathname.endsWith(".ts") || pathname.endsWith(".tsx"))) {
|
}
|
||||||
const response = await serveFile(req, "./" + pathname);
|
|
||||||
return await transpileResponse(response, req.url, pathname);
|
async function* siteEntries(path: string): AsyncGenerator<string> {
|
||||||
} else if (pathname.startsWith("/deps")) {
|
for await (const dirEnt of Deno.readDir(path)) {
|
||||||
return serveFile(req, `node_modules/${pathname.split("/deps")[1]}`);
|
if (dirEnt.isDirectory) {
|
||||||
|
yield* siteEntries(join(path, dirEnt.name));
|
||||||
|
} else if (dirEnt.name === "index_template.html") {
|
||||||
|
yield path.split("/")[1] ?? "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const publicFiles = siteEntries("public");
|
||||||
|
const sites: string[] = [];
|
||||||
|
for await (const path of publicFiles) {
|
||||||
|
sites.push(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAPIResponse(apiReq: Request): Response {
|
||||||
|
let jsonResponse: DJAPIResult | { error: string } | null = null;
|
||||||
|
let status = 200;
|
||||||
|
|
||||||
|
const pathname = URL.parse(apiReq.url)?.pathname;
|
||||||
|
|
||||||
|
if (!pathname) {
|
||||||
|
jsonResponse = { error: "Invalid Route" };
|
||||||
|
status = 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jsonResponse && pathname) {
|
||||||
|
const apiPath = pathname.split("/api")[1];
|
||||||
|
|
||||||
|
if (apiPath === "/rp-articles") {
|
||||||
|
jsonResponse = [
|
||||||
|
{ name: "Koffein: ein vitamin-ähnlicher Nährstoff, oder Adaptogen", slug: "caffeine" },
|
||||||
|
{
|
||||||
|
name: "TSH, Temperatur, Puls, und andere Indikatoren bei einer Schilddrüsenunterfunktion",
|
||||||
|
slug: "hypothyroidism",
|
||||||
|
},
|
||||||
|
] satisfies DJAPIResultMap["/rp-articles"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = new Headers();
|
||||||
|
headers.set("Content-Type", "application/json");
|
||||||
|
return new Response(JSON.stringify(jsonResponse), {
|
||||||
|
status,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Deno.serve({
|
||||||
|
port: 8080,
|
||||||
|
hostname: "0.0.0.0",
|
||||||
|
onListen({ port, hostname }) {
|
||||||
|
console.log(`Listening on port http://${hostname}:${port}/`);
|
||||||
|
},
|
||||||
|
}, async (req, _conn) => {
|
||||||
|
let response: Response | null = null;
|
||||||
|
|
||||||
|
if (req.method === "GET") {
|
||||||
|
const pathname = URL.parse(req.url)?.pathname ?? "/";
|
||||||
|
|
||||||
|
if (pathname.startsWith("/api/")) {
|
||||||
|
response = getAPIResponse(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public/static files
|
||||||
|
if (!response) {
|
||||||
|
let filepath = join(".", "public", pathname);
|
||||||
|
if (filepath.endsWith("/")) {
|
||||||
|
filepath = join(filepath, "index.html");
|
||||||
|
}
|
||||||
|
if (await exists(filepath, { isFile: true })) {
|
||||||
|
response = await serveFile(req, filepath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NPM Vendor deps
|
||||||
|
if (response === null && pathname.startsWith("/deps")) {
|
||||||
|
response = await serveFile(req, `node_modules/${pathname.split("/deps")[1]}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transpile Code
|
||||||
|
if (
|
||||||
|
response === null &&
|
||||||
|
pathname.startsWith("/app") &&
|
||||||
|
(pathname.endsWith(".ts") || pathname.endsWith(".tsx")) &&
|
||||||
|
!pathname.endsWith("server.ts")
|
||||||
|
) {
|
||||||
|
response = await serveFile(req, "./" + pathname);
|
||||||
|
response = await transpileResponse(response, req.url, pathname);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSR
|
||||||
|
if (response === null) {
|
||||||
|
const baseDirectoryName = pathname.split("/")[1] ?? "";
|
||||||
|
if (sites.includes(baseDirectoryName)) {
|
||||||
|
const appLocation = baseDirectoryName === "" ? "home" : baseDirectoryName;
|
||||||
|
const siteTemplate = join("public", baseDirectoryName, "index_template.html");
|
||||||
|
const siteEntry = join("app", appLocation, "server.ts");
|
||||||
|
const clientEntry = join("@", appLocation, "client.ts");
|
||||||
|
const { app, router } = (await import("./" + siteEntry)).default() as {
|
||||||
|
app: App;
|
||||||
|
router: Router | null;
|
||||||
|
};
|
||||||
|
app.provide("dom-parse", (innerHTML: string) => {
|
||||||
|
return parser.parseFromString(innerHTML, "text/html").documentElement;
|
||||||
|
});
|
||||||
|
const ssrContext: DJSSRContext = { registry: {}, head: { title: "" } };
|
||||||
|
if (router) {
|
||||||
|
await router.replace(pathname.split("/generative-energy")[1]);
|
||||||
|
await router.isReady();
|
||||||
|
}
|
||||||
|
const rendered = await renderToString(app, ssrContext);
|
||||||
|
const content = utf8Decoder.decode(await Deno.readFile(siteTemplate))
|
||||||
|
.replace(`<!-- SSR OUTLET -->`, rendered)
|
||||||
|
.replaceAll("%TITLE%", toValue(ssrContext.head?.title) ?? "Site")
|
||||||
|
.replace(
|
||||||
|
`<!-- SSR HEAD OUTLET -->`,
|
||||||
|
appHeaderScript({ appstate: ssrContext.registry, entryPath: clientEntry }),
|
||||||
|
);
|
||||||
|
response = new Response(content, { headers: { "Content-Type": "text/html" } });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new Response("Not found.", { status: 404 });
|
|
||||||
} else {
|
} else {
|
||||||
return new Response("Only GET allowed.", { status: 500 });
|
response = new Response("Only GET allowed.", { status: 500 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return response ?? new Response("Not found.", { status: 404 });
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.addSignalListener("SIGINT", () => {
|
Deno.addSignalListener("SIGINT", () => {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<h1>
|
<h1 lang="en">Caffeine: A vitamin-like nutrient, or adaptogen</h1>
|
||||||
<span lang="en">Caffeine: A vitamin-like nutrient, or adaptogen</span>
|
<h1 lang="de">Koffein: ein vitamin-ähnlicher Nährstoff, oder Adaptogen</h1>
|
||||||
<span lang="de">Koffein: ein vitamin-ähnlicher Nährstoff, oder Adaptogen</span>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<span lang="en"><strong>Questions about tea and coffee, cancer and other degenerative diseases, and the hormones.</strong></span>
|
<span lang="en"><strong>Questions about tea and coffee, cancer and other degenerative diseases, and the hormones.</strong></span>
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>%TITLE%</title>
|
<title>%TITLE%</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="/generative-energy/static/styles.css">
|
<link rel="stylesheet" href="/generative-energy/styles.css">
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Roboto&family=Roboto+Slab:wght@600&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Roboto&family=Roboto+Slab:wght@600&display=swap"
|
||||||
rel="stylesheet">
|
rel="stylesheet">
|
||||||
@@ -139,17 +139,26 @@ hr {
|
|||||||
background: #999;
|
background: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
footer .bottom {
|
footer {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.bottom {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.dj-donate {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.ge-calculator {
|
.ge-calculator {
|
||||||
table {
|
table {
|
||||||
@@ -186,13 +195,3 @@ footer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-enter-active,
|
|
||||||
.fade-leave-active {
|
|
||||||
transition: opacity 0.5s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-enter-from,
|
|
||||||
.fade-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
0
public/home/img/.gitignore
vendored
Normal file
BIN
public/home/img/daniel.jpg
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
public/home/img/dj.gif
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
public/home/img/icon.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
public/home/img/preis.jpg
Normal file
|
After Width: | Height: | Size: 384 KiB |
BIN
public/home/img/tile-wide.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
public/home/img/tile.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
public/home/img/tradies.png
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
public/home/img/worksafe.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
@@ -1,18 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>G'day</title>
|
|
||||||
<link rel="icon" href="icon.webp" />
|
|
||||||
<link rel="stylesheet" href="/static/styles.css" />
|
|
||||||
<!-- SSR HEAD OUTLET -->
|
|
||||||
<script type="module" src="/static/app.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<main class="container">
|
|
||||||
<h1>G'day, mate!</h1>
|
|
||||||
<h2>YOUR SITE GOES HERE</h2>
|
|
||||||
<img src="/static/image.jpeg" alt="KANGAROO" />
|
|
||||||
<div id="app-root"><!-- SSR OUTLET --></div>
|
|
||||||
</main>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
130
public/home/js/SexyTooltip.ts
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
interface Point {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Size {
|
||||||
|
height: string;
|
||||||
|
width: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SexyTooltip {
|
||||||
|
private static readonly carrierStyle: Partial<CSSStyleDeclaration> = {
|
||||||
|
opacity: "0",
|
||||||
|
display: "block",
|
||||||
|
pointerEvents: "none",
|
||||||
|
backgroundColor: "black",
|
||||||
|
border: "white solid 1px",
|
||||||
|
color: "white",
|
||||||
|
padding: "10px",
|
||||||
|
position: "absolute",
|
||||||
|
zIndex: "1",
|
||||||
|
overflow: "hidden",
|
||||||
|
height: "0",
|
||||||
|
width: "0",
|
||||||
|
transition: "opacity 200ms, height 200ms, width 200ms",
|
||||||
|
};
|
||||||
|
private static readonly textCarrierStyle: Partial<CSSStyleDeclaration> = {
|
||||||
|
width: "350px",
|
||||||
|
display: "block",
|
||||||
|
overflow: "hidden",
|
||||||
|
};
|
||||||
|
private static readonly defaultWidth = 350;
|
||||||
|
private readonly carrier: HTMLDivElement;
|
||||||
|
private readonly textCarrier: HTMLSpanElement;
|
||||||
|
private readonly elementsWithTooltips: Element[] = [];
|
||||||
|
private active: boolean = false;
|
||||||
|
|
||||||
|
constructor(carrier: HTMLDivElement) {
|
||||||
|
if (carrier.childNodes.length > 0) {
|
||||||
|
throw new Error("Incorrect setup for tooltip! Remove the child nodes from the tooltip div.");
|
||||||
|
}
|
||||||
|
this.carrier = carrier;
|
||||||
|
this.textCarrier = document.createElement("span");
|
||||||
|
this.carrier.appendChild(this.textCarrier);
|
||||||
|
Object.assign(this.carrier.style, SexyTooltip.carrierStyle);
|
||||||
|
Object.assign(this.textCarrier.style, SexyTooltip.textCarrierStyle);
|
||||||
|
document.querySelectorAll(".tooltip").forEach((element) => {
|
||||||
|
if (element.nodeName === "SPAN") {
|
||||||
|
console.log(element.previousElementSibling);
|
||||||
|
this.elementsWithTooltips.push(element.previousElementSibling);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.addEventListener("mousemove", (event) => this.rerenderTooltip({ x: event.pageX, y: event.pageY }));
|
||||||
|
}
|
||||||
|
|
||||||
|
rerenderTooltip(mousePos: Point) {
|
||||||
|
const newText = this.getTooltipTextForHoveredElement(mousePos);
|
||||||
|
if (newText !== this.textCarrier.innerHTML) {
|
||||||
|
this.transitionTooltipSize(newText);
|
||||||
|
const tooltipHasText = newText !== "";
|
||||||
|
if (tooltipHasText !== this.active) {
|
||||||
|
this.toggleActive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.isStillVisible()) {
|
||||||
|
this.updatePosition(mousePos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isStillVisible() {
|
||||||
|
return getComputedStyle(this.carrier).opacity !== "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePosition(pos: Point) {
|
||||||
|
if (pos.x + 15 + this.carrier.clientWidth <= document.body.scrollWidth) {
|
||||||
|
this.carrier.style.left = (pos.x + 15) + "px";
|
||||||
|
} else {
|
||||||
|
this.carrier.style.left = (document.body.scrollWidth - this.carrier.clientWidth - 5) + "px";
|
||||||
|
}
|
||||||
|
if (pos.y + this.carrier.clientHeight <= document.body.scrollHeight) {
|
||||||
|
this.carrier.style.top = pos.y + "px";
|
||||||
|
} else {
|
||||||
|
this.carrier.style.top = (document.body.scrollHeight - this.carrier.clientHeight - 5) + "px";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleActive() {
|
||||||
|
if (this.active) {
|
||||||
|
this.active = false;
|
||||||
|
this.carrier.style.opacity = "0";
|
||||||
|
this.carrier.style.padding = "0";
|
||||||
|
} else {
|
||||||
|
this.active = true;
|
||||||
|
this.carrier.style.opacity = "1";
|
||||||
|
this.carrier.style.padding = SexyTooltip.carrierStyle.padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transitionTooltipSize(text: string) {
|
||||||
|
const testDiv = document.createElement("div");
|
||||||
|
testDiv.style.height = "auto";
|
||||||
|
testDiv.style.width = SexyTooltip.defaultWidth + "px";
|
||||||
|
testDiv.innerHTML = text;
|
||||||
|
document.body.appendChild(testDiv);
|
||||||
|
const calculatedHeight = testDiv.scrollHeight;
|
||||||
|
testDiv.style.display = "inline";
|
||||||
|
testDiv.style.width = "auto";
|
||||||
|
document.body.removeChild(testDiv);
|
||||||
|
const size = { height: calculatedHeight + "px", width: "350px" };
|
||||||
|
this.carrier.style.height = size.height;
|
||||||
|
this.carrier.style.width = text === "" ? "0" : size.width;
|
||||||
|
this.textCarrier.innerHTML = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTooltipTextForHoveredElement(mousePos: Point): string {
|
||||||
|
for (const elem of this.elementsWithTooltips) {
|
||||||
|
const boundingRect = elem.getBoundingClientRect();
|
||||||
|
const inYRange = mousePos.y >= boundingRect.top + window.pageYOffset - 1 &&
|
||||||
|
mousePos.y <= boundingRect.bottom + window.pageYOffset + 1;
|
||||||
|
const inXRange = mousePos.x >= boundingRect.left + window.pageXOffset - 1 &&
|
||||||
|
mousePos.x <= boundingRect.right + window.pageXOffset + 1;
|
||||||
|
if (inYRange && inXRange) {
|
||||||
|
return (elem.nextElementSibling as HTMLSpanElement)?.innerText ?? "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SexyTooltip;
|
||||||
47
public/home/js/main.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import SexyTooltip from "./SexyTooltip.js";
|
||||||
|
|
||||||
|
const tooltipDiv = document.getElementById("tooltipCarrier") as HTMLDivElement;
|
||||||
|
const tooltip = new SexyTooltip(tooltipDiv);
|
||||||
|
|
||||||
|
const dudes = document.querySelectorAll(".dude") as NodeListOf<HTMLImageElement>;
|
||||||
|
const shakers = document.querySelectorAll(".shakeable") as NodeListOf<HTMLElement>;
|
||||||
|
const emailLink = document.getElementById("emailLink") as HTMLAnchorElement;
|
||||||
|
let numDudesDroppingSickBeats: number = 0;
|
||||||
|
|
||||||
|
dudes.forEach((dude) => dude.addEventListener("mouseup", () => toggleDude(dude)));
|
||||||
|
|
||||||
|
function toggleDude(dude: HTMLImageElement) {
|
||||||
|
if (dude.classList.contains("spinMe")) {
|
||||||
|
numDudesDroppingSickBeats -= 1;
|
||||||
|
dude.addEventListener("animationiteration", function listener() {
|
||||||
|
dude.classList.remove("spinMe");
|
||||||
|
dude.removeEventListener("animationiteration", listener as EventListenerOrEventListenerObject);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
numDudesDroppingSickBeats += 1;
|
||||||
|
dude.classList.add("spinMe");
|
||||||
|
}
|
||||||
|
updateShakers();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateShakers() {
|
||||||
|
shakers.forEach((shaker) => {
|
||||||
|
if (numDudesDroppingSickBeats === 0) {
|
||||||
|
shaker.classList.remove("shakeMe");
|
||||||
|
} else if (!shaker.classList.contains("shakeMe")) {
|
||||||
|
shaker.classList.add("shakeMe");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
emailLink.addEventListener("click", (event) => {
|
||||||
|
const myDomain = "gmail";
|
||||||
|
const myTld = "com";
|
||||||
|
const myName = "danjledda";
|
||||||
|
const dot = ".";
|
||||||
|
const at = "@";
|
||||||
|
let link = "mailto:" + myName + myDomain + myTld;
|
||||||
|
link = link.slice(0, 10) + dot + link.slice(10, 11) + dot + link.slice(11, 16) + at + link.slice(16, 21) + dot +
|
||||||
|
link.slice(21);
|
||||||
|
window.location.href = link;
|
||||||
|
});
|
||||||
189
public/home/main.css
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
:root {
|
||||||
|
--subject-spacing: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #292929;
|
||||||
|
font-family: "Roboto", serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title_name {
|
||||||
|
font-size: 50px;
|
||||||
|
color: floralwhite;
|
||||||
|
font-family: "Roboto Slab", "Times New Roman", Times, serif;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title_name img {
|
||||||
|
margin: 20px;
|
||||||
|
height: 100px;
|
||||||
|
width: auto;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinMe {
|
||||||
|
animation: spin 1s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shakeMe {
|
||||||
|
animation: shake 0.2s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shake {
|
||||||
|
0% {
|
||||||
|
transform: scale(1) translate(1px, 1px) rotate(0deg);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: scale(0.95) translate(-1px, -2px) rotate(-1deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(0.9) translate(-3px, 0px) rotate(1deg);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: scale(0.95) translate(3px, 2px) rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1) translate(-1px, 2px) rotate(-1deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg) scale(1);
|
||||||
|
filter: hue-rotate(0deg) saturate(5);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: rotate(90deg) scale(2);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: rotate(180deg) scale(1);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: rotate(270deg) scale(2);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg) scale(1);
|
||||||
|
filter: hue-rotate(360deg) saturate(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.supercontainer {
|
||||||
|
padding-top: 3em;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
width: 50em;
|
||||||
|
margin: 20px auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1024px) {
|
||||||
|
.main {
|
||||||
|
width: 35em;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
:root {
|
||||||
|
--subject-spacing: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 768px) {
|
||||||
|
.title_name img {
|
||||||
|
margin: 10px;
|
||||||
|
height: 60px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
.title_name {
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
.main {
|
||||||
|
width: 20em;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span.subjecttitle {
|
||||||
|
height: 100%;
|
||||||
|
font-family: "Roboto Slab", "Times New Roman", Times, serif;
|
||||||
|
font-size: 20px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subject:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subject:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subject {
|
||||||
|
margin-top: var(--subject-spacing);
|
||||||
|
margin-bottom: var(--subject-spacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resourcelist {
|
||||||
|
margin-top: 2px;
|
||||||
|
background-color: white;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #292929;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
a:first-of-type {
|
||||||
|
.resource {
|
||||||
|
padding: 15px 20px 10px 20px;
|
||||||
|
border-radius: 5px 5px 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a:last-of-type {
|
||||||
|
.resource {
|
||||||
|
padding: 10px 20px 15px 20px;
|
||||||
|
border-radius: 0 0 5px 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a:only-of-type {
|
||||||
|
.resource {
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource {
|
||||||
|
position: relative;
|
||||||
|
background-color: white;
|
||||||
|
padding: 10px 20px 10px 20px;
|
||||||
|
display: block;
|
||||||
|
color: #333333;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background-color 200ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource:hover {
|
||||||
|
background-color: #bde4ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource:active {
|
||||||
|
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.50) inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #000;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-container {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
32
public/home/muenchen-auf-englisch.html
Normal file
740
public/home/ortsteile_muc_en.html
Normal file
@@ -0,0 +1,740 @@
|
|||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
|
||||||
|
<title></title>
|
||||||
|
<meta name="generator" content="LibreOffice 6.0.7.3 (Linux)"/>
|
||||||
|
<meta name="created" content="2020-06-26T11:18:35.466195148"/>
|
||||||
|
<meta name="changed" content="2020-06-29T14:58:13.220640138"/>
|
||||||
|
<style type="text/css">
|
||||||
|
@page { margin: 0.79in }
|
||||||
|
p { margin-bottom: 0.1in; line-height: 115% }
|
||||||
|
td p { margin-bottom: 0in }
|
||||||
|
a:link { so-language: zxx }
|
||||||
|
table, th, td { border: 1px solid black !important }
|
||||||
|
td { padding: 10px !important }
|
||||||
|
td { width: auto !important; height: auto !important }
|
||||||
|
table { border-collapse: collapse }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body lang="en-US" dir="ltr">
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Allach">Allach</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Axleigh
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>Ahaloh → Allach, Aha → Axe, Loh → Leigh (“Aha + lohe”
|
||||||
|
→ “Flusslichtung”)</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" height="22" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Altstadt_(M%C3%BCnchen)">Altstadt</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Oldstead</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Am_Hart">Am Hart</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>At the Woods</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Am_Moosfeld">Am Moosfeld</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>At the Mossfield</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Am_Riesenfeld">Am
|
||||||
|
Riesenfeld</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>At the Giantfield</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Au_(M%C3%BCnchen)">Au</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Ey</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">as in “Romsey”,
|
||||||
|
“Athelney”, “Beverley Hills”</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Aubing">Aubing</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Eving</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Kein Beleg für Herkunft,
|
||||||
|
erste Ewähnung 16. April 1010 unter “Ubingun”. Bajuwarischer
|
||||||
|
Name “Ubo” könnte naheliegen.</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Berg_am_Laim">Berg am
|
||||||
|
Laim</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Loam Hill</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Bogenhausen">Bogenhausen</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Bobehouse</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Bajuware Pubo, Pupi</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Daglfing">Daglfing</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Dighelfing /daɪəlfɪŋ/
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Bajuware Tagolf/Thachulf</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Denning_(M%C3%BCnchen)">Denning</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Denning </span>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Bajuware Tenno</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Englschalking">Englschalking</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Angelshalking</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">(en. <i>shalk </i>→ a
|
||||||
|
servant; Englschalch → “strenger Knecht”)</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Fasangarten">Fasangarten</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Pheasantgarden</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Feldmoching">Feldmoching</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Field Mocking </span>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Feld der Anhänger des
|
||||||
|
Mocho, imagined as en. Mocko</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Forstenried">Forstenried</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Forestley</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Freiham">Freiham</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Freeham</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Freimann">Freimann</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Freeman</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/F%C3%BCrstenried">Fürstenried</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Princeley</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Obergiesing">Obergiesing</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Upper </span><span style="background: transparent">Kye</span><span style="background: transparent">sing
|
||||||
|
/</span><span style="background: transparent">ka</span>ɪz<span style="background: transparent">ɪŋ/
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Bajuware </span><span style="background: transparent">Kyso
|
||||||
|
→</span><span style="background: transparent"> </span><span style="background: transparent">perhaps
|
||||||
|
en. </span><i><span style="background: transparent">Kyeso
|
||||||
|
</span></i><span style="font-style: normal"><span style="background: transparent">(/</span></span><span style="font-style: normal"><span style="background: transparent">ka</span></span><span style="font-style: normal"><span style="background: transparent">ɪ</span></span><span style="font-style: normal"><span style="background: transparent">z</span></span><span style="font-style: normal"><span style="background: transparent">oʊ/)</span></span><span style="background: transparent">?
|
||||||
|
K and S stay the same, </span><span style="background: transparent">ahd.
|
||||||
|
</span><i><span style="background: transparent">y</span></i><span style="background: transparent">
|
||||||
|
is interchangeable with </span><i><span style="background: transparent">i</span></i><span style="background: transparent">,
|
||||||
|
probably </span><span style="background: transparent">would have
|
||||||
|
become /</span><span style="background: transparent">a</span><span style="background: transparent">ɪ</span><span style="background: transparent">/</span><span style="background: transparent">)</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Untergiesing">Untergiesing</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Lower Kyesing</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Hadern">Hadern</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Hathern /hei</span>ð<span style="background: transparent">ɜ:</span><span style="background: transparent">n/</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Von ahd. </span><i><span style="background: transparent">Haderun
|
||||||
|
</span></i><span style="background: transparent">(“bei den
|
||||||
|
Waldleuten”</span><span style="background: transparent">)</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/w/index.php?title=Holzapfelkreuth&action=edit&redlink=1">Holzapfelkreuth</a>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Woodapple Glade</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Kreuth → <i>das
|
||||||
|
Gereutete</i>, nhd. <i>Gerodete</i>, related to “rid” → a
|
||||||
|
clearing, “rid of trees”</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Haidhausen">Haidhausen</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p><span style="background: transparent">Heathhouse</span></p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Harlaching">Harlaching</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Heathleighing
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>Von ahd. <i>Hadaleih </i>+ <i>ing →</i><span style="font-style: normal">gleich:
|
||||||
|
“Heide + lohe + ing”</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Hasenbergl">Hasenbergl</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Hare Hill</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Isarvorstadt">Isarvorstadt</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Isar Forestead</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Johanneskirchen_(M%C3%BCnchen)">Johanneskirchen</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Johnkirk</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>en. -<i>kirk → </i><span style="font-style: normal">Church</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Laim">Laim</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Loam</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>Laim = nhd. <i>Lehm = </i><span style="font-style: normal">en.
|
||||||
|
</span><i>Loam</i></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Langwied_(M%C3%BCnchen)">Langwied</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Longwood</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>Wied → ahd. witu “Wald”, en. “wood”</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Lehel_(M%C3%BCnchen)">Lehel</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Fief
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>(von nhd. <i>Lehen</i><span style="font-style: normal">,</span><i>
|
||||||
|
</i>cf. en. <i>Loan</i>)</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Lochhausen_(M%C3%BCnchen)">Lochhausen</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Lockhouse</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Ludwigsvorstadt">Ludwigsvorstadt</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Ludwig Forestead</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Maxvorstadt">Maxvorstadt</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Max Forestead</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Milbertshofen_(Bezirksteil)">Milbertshofen</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Ilvinghope
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>ca. 1149 “Ilmungeshoven” von Bajuware
|
||||||
|
Ilbunch/Ilbung/Ilmung. War Einsiedlerhof, auf den man ausgesiedelt
|
||||||
|
wurde wegen Krankheit oder als Strafe → aussprache wurde
|
||||||
|
absichtlich undeutlich um die Beziehung zu diesem Dorf zu
|
||||||
|
verstecken.
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p> <a href="https://de.wikipedia.org/wiki/Moosach_(M%C3%BCnchen)">Moosach</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Moorey</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>Moor + ach (“Au”). R wird zu S durch Rhotazismus (cf.
|
||||||
|
frieren → Frost, verlieren → Verlust, waren → gewesen)</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Neuhausen_(M%C3%BCnchen)">Neuhausen</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Newhouse</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Nymphenburg_(M%C3%BCnchen)">Nymphenburg</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Nymphbury</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Oberf%C3%B6hring">Oberföhring</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Upper Fairing</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>Bajuware Fero</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Obermenzing">Obermenzing</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Upper Menting</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>Bajuware Manzo (wegen -ing umgelautet)</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Pasing">Pasing</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Paising /peɪzɪŋ/</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>Bajuware Paoso, Paso</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Perlach_(M%C3%BCnchen)">Perlach</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Pearley</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Ramersdorf_(M%C3%BCnchen)">Ramersdorf</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Rammlethorpe /ræməlθɔ:p/
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>“Rumoltesdorf” ca. 1006. Kein Fugen-S im Englischen</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Riem">Riem</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Rim</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>cf. “Pacific Rim”</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Schwabing">Schwabing</a>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Swabing /sweɪbɪŋ/</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>Bajuware Swapo</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Schwanthalerh%C3%B6he">Schwanthalerhöhe</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Swandale Heights</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Sendling">Sendling</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Senthling</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>Bajuware Sentilo</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Solln">Solln</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Soal</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>Also closely related: en. soil, slough</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Steinhausen_(M%C3%BCnchen)">Steinhausen</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Stonehouse</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Thalkirchen">Thalkirchen</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Dalekirk</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Trudering">Trudering</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Droughthring /drauθrɪŋ/
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p>Bajuware Truchtaro/Truhtheri/Drudheri/Tructeri</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Untermenzing">Untermenzing</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Lower Menting</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="122" style="border: none; padding: 0in">
|
||||||
|
<p><a href="https://de.wikipedia.org/wiki/Zamdorf">Zamdorf</a></p>
|
||||||
|
</td>
|
||||||
|
<td width="188" style="border: none; padding: 0in">
|
||||||
|
<p>Tamthorpe /tæmθɔ:p/</p>
|
||||||
|
</td>
|
||||||
|
<td width="344" style="border: none; padding: 0in">
|
||||||
|
<p><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%">Quellen:</p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%">Wikipedia Seiten zu
|
||||||
|
den jeweiligen Orten</p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%">Wiktionary fuer
|
||||||
|
einige Rueckbildungen (zB Slough, Rim, Long<b>weed</b><span style="font-weight: normal">,
|
||||||
|
Loam, Angel</span><b>shalk</b><span style="font-weight: normal">ing)</span></p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><a href="https://en.wikipedia.org/wiki/List_of_generic_forms_in_place_names_in_Ireland_and_the_United_Kingdom">https://en.wikipedia.org/wiki/List_of_generic_forms_in_place_names_in_Ireland_and_the_United_Kingdom</a></p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><a href="https://de.wikipedia.org/wiki/Kategorie:Ortsnamen-Endung">https://de.wikipedia.org/wiki/Kategorie:Ortsnamen-Endung</a></p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><a href="http://www.fam-schweden.de/Muenchen/muenchen.html">http://www.fam-schweden.de/Muenchen/muenchen.html</a></p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><a href="https://de.wikipedia.org/wiki/Zweite_Lautverschiebung#Phase_1">https://de.wikipedia.org/wiki/Zweite_Lautverschiebung#Phase_1</a></p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><a href="https://www.munichkindl.net/besiedlung">https://www.munichkindl.net/besiedlung</a></p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><a href="https://www.gutenberg.org/files/22636/22636-h/22636-h.htm">https://www.gutenberg.org/files/22636/22636-h/22636-h.htm</a></p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p style="margin-bottom: 0in; line-height: 100%"><br/>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
.container {
|
|
||||||
margin: auto;
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
|
||||||
background-color: #fffafa;
|
|
||||||
box-shadow: #000000;
|
|
||||||
padding-top: 10px;
|
|
||||||
min-height: calc(100vh - 10px);
|
|
||||||
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.2);
|
|
||||||
|
|
||||||
@media (min-width: 992px) {
|
|
||||||
width: 900px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
88
public/index2.html
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>DJ Ledda's Homepage</title>
|
||||||
|
<meta name="description" content="the coolest homepage in the whole galaxy" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
|
<link rel="manifest" href="site.webmanifest" />
|
||||||
|
<link rel="icon" href="img/dj.gif" />
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/main.css" />
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Roboto&family=Roboto+Slab:wght@600&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<meta name="theme-color" content="#fafafa" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!--[if IE]>
|
||||||
|
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="https://browsehappy.com/">upgrade your browser</a> to improve your experience and security.</p>
|
||||||
|
<![endif]-->
|
||||||
|
|
||||||
|
<!-- Site Content -->
|
||||||
|
<div class="supercontainer">
|
||||||
|
<div class="shakeable">
|
||||||
|
<div class="title_name">
|
||||||
|
<img src="img/dj.gif" alt="dj legt krasse Mucke auf" class="dude" />
|
||||||
|
<span class="tooltip">I wonder what he's listening to?</span>
|
||||||
|
<span>DJ Ledda</span>
|
||||||
|
<span class="tooltip">Easily the coolest guy out there.</span>
|
||||||
|
<img src="img/dj.gif" alt="dj laying down some sick beats" class="dude" />
|
||||||
|
<span class="tooltip">I once heard this guy played at revs.</span>
|
||||||
|
</div>
|
||||||
|
<div class="main">
|
||||||
|
<div class="subject">
|
||||||
|
<div class="resourcelist">
|
||||||
|
<a class="resource" href="https://drum-slayer.com">
|
||||||
|
Drum Slayer
|
||||||
|
</a>
|
||||||
|
<span class="tooltip"
|
||||||
|
>Small app for designing multitrack looped rhythms with local save and multiple files.
|
||||||
|
Originally built using just vanilla TypeScript and CSS, now with Vue.</span>
|
||||||
|
<a class="resource" href="/somaesque">
|
||||||
|
Somaesque
|
||||||
|
</a>
|
||||||
|
<span class="tooltip"
|
||||||
|
>Puzzle solver app for puzzle cubes resembling the original Soma Cube puzzle. Save and edit
|
||||||
|
your own puzzles! Built with Svelte, THREE.js and AssemblyScript.</span>
|
||||||
|
<a class="resource" href="/generative-energy">
|
||||||
|
Generative Energy - Ray Peat Resources
|
||||||
|
</a>
|
||||||
|
<span class="tooltip">Thyroid calculator, German translations, and more...</span>
|
||||||
|
<a class="resource" href="/muenchen-auf-englisch.html">
|
||||||
|
München auf Englisch - Munich in English
|
||||||
|
</a>
|
||||||
|
<span class="tooltip"
|
||||||
|
>Authentic historically accurate translations of all of Munich's S-Bahn and U-Bahn stations,
|
||||||
|
as well as the main municipalities, into English. You live in Allach? It's Axleigh now.
|
||||||
|
Giesing? Nope! Kyesing! This is a WIP.</span>
|
||||||
|
<a class="resource" href="/kadi/">
|
||||||
|
K A D I: Online Yatzy Scoresheets
|
||||||
|
</a>
|
||||||
|
<span class="tooltip"
|
||||||
|
>Make an account and start saving paper and tracking your Yatzy stats with your friends!
|
||||||
|
Make your own rulesets, and more. Built with React, express.js, and MongoDB. Currently
|
||||||
|
inactive.</span>
|
||||||
|
<a class="resource" href="http://git.djledda.de/Ledda">
|
||||||
|
My git projects
|
||||||
|
</a>
|
||||||
|
<span class="tooltip">Check out what I'm coding!</span>
|
||||||
|
<a id="emailLink" class="resource">
|
||||||
|
Click here to get in touch
|
||||||
|
</a>
|
||||||
|
<span class="tooltip">You'll see my address when you click here.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="tooltipCarrier"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- End Content -->
|
||||||
|
|
||||||
|
<script src="js/main.js" type="module"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
18
public/index_template.html
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>G'day</title>
|
||||||
|
<link rel="icon" href="/home/icon.webp" />
|
||||||
|
<link rel="stylesheet" href="/home/main.css" />
|
||||||
|
<link rel="icon" href="img/dj.gif" />
|
||||||
|
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Roboto&family=Roboto+Slab:wght@600&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<!-- SSR HEAD OUTLET -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app-root"><!-- SSR OUTLET --></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
5
public/robots.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# www.robotstxt.org/
|
||||||
|
|
||||||
|
# Allow crawling of all content
|
||||||
|
User-agent: *
|
||||||
|
Disallow:
|
||||||