update
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { nextTick, inject, provide, watch, type InjectionKey, onBeforeUnmount, watchEffect, onMounted, type Ref, type CSSProperties, defineComponent, ref } from "vue";
|
||||
import { h as djh } from "@/util.ts";
|
||||
import { addCSS, css, h as djh } from "@/util.ts";
|
||||
|
||||
type TooltipContext = {
|
||||
show: (newText: string, x: number, y: number) => void,
|
||||
@@ -8,9 +8,42 @@ type TooltipContext = {
|
||||
|
||||
const tooltipContext = Symbol('tooltip') as InjectionKey<TooltipContext>;
|
||||
|
||||
const tooltipStyles = css`
|
||||
.tooltip-container {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.tooltip-carrier {
|
||||
opacity: 0;
|
||||
display: block;
|
||||
pointer-events: none;
|
||||
background-color: black;
|
||||
border: white solid 1px;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
transition: opacity 200ms, height 200ms, width 200ms;
|
||||
|
||||
.text-carrier {
|
||||
position: absolute;
|
||||
width: 350px;
|
||||
font-size: 16px;
|
||||
font-family: "Roboto", serif;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
}`;
|
||||
|
||||
export function setupTooltip(options: { carrier: Ref<HTMLElement | null> }) {
|
||||
const { carrier } = options;
|
||||
|
||||
addCSS('tooltip-carrier', tooltipStyles);
|
||||
|
||||
watchEffect(() => {
|
||||
if (carrier.value) {
|
||||
carrier.value.classList.add('tooltip-carrier');
|
||||
@@ -82,6 +115,8 @@ export default defineComponent({
|
||||
setup(props, { slots, attrs }) {
|
||||
const tooltip = inject(tooltipContext, () => { throw new Error('No tooltip context'); }, true);
|
||||
|
||||
onBeforeUnmount(() => tooltip.hide());
|
||||
|
||||
return () => <>
|
||||
<div class="tooltip-container"
|
||||
{...attrs}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export type DJAPIEndpoint = "/rp-articles";
|
||||
|
||||
export interface DJAPIResultMap extends Record<DJAPIEndpoint, unknown> {
|
||||
"/rp-articles": { slug: string; name: string }[];
|
||||
"/rp-articles": { slug: string; title: string, tags?: string[] }[];
|
||||
}
|
||||
|
||||
export type DJAPIResult = DJAPIResultMap[DJAPIEndpoint];
|
||||
|
||||
1
app/devtools-shim.ts
Normal file
1
app/devtools-shim.ts
Normal file
@@ -0,0 +1 @@
|
||||
export function setupDevtoolsPlugin() {}
|
||||
@@ -17,17 +17,17 @@ export default defineComponent({
|
||||
step: 0.1,
|
||||
},
|
||||
{
|
||||
name: "Armour, Natural Dessicated Thyroid",
|
||||
name: 'Natural Dessicated Thyroid ("Armour")',
|
||||
mpg: 60,
|
||||
unit: "mg",
|
||||
},
|
||||
{
|
||||
name: 'Liothyronine (Triiodothyronine, "Cytomel/Cynomel", T3)',
|
||||
name: 'Liothyronine (T3 - "Cytomel/Cynomel")',
|
||||
mpg: MPG_T3_SYN,
|
||||
unit: "mcg",
|
||||
},
|
||||
{
|
||||
name: "Levothyroxine (Thyroxine, T4)",
|
||||
name: "Levothyroxine (T4)",
|
||||
mpg: MPG_T4_SYN,
|
||||
unit: "mcg",
|
||||
},
|
||||
@@ -67,7 +67,7 @@ export default defineComponent({
|
||||
{inputDefs.map((_) => (
|
||||
<tr key={_.name}>
|
||||
<td>
|
||||
{_.name}
|
||||
{_.name}{_.unit && (', ' + _.unit)}
|
||||
</td>
|
||||
<td class="right">
|
||||
<div style="display: inline-block;">
|
||||
@@ -86,20 +86,19 @@ export default defineComponent({
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
<span class="breathe">{_.unit}</span>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<strong>Compounded (T3 and T4, "Cynoplus")</strong>
|
||||
<strong>Compounded (T3 and T4 - "Cynoplus")</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="ratios">
|
||||
<td>
|
||||
Desired Ratio (T3:T4)
|
||||
</td>
|
||||
<td class="right">
|
||||
<td class="right ratio">
|
||||
<div>
|
||||
<input
|
||||
value={t3Ratio.value}
|
||||
@@ -110,8 +109,8 @@ export default defineComponent({
|
||||
step="1"
|
||||
type="number"
|
||||
/>
|
||||
</div>{" "}
|
||||
:{" "}
|
||||
</div>
|
||||
<span class="separator"/>
|
||||
<div>
|
||||
<input
|
||||
value={t4Ratio.value}
|
||||
@@ -127,9 +126,9 @@ export default defineComponent({
|
||||
</tr>
|
||||
<tr class="synthetic">
|
||||
<td>
|
||||
Synthetic T3/T4 Combo
|
||||
T3 mcg : T4 mcg
|
||||
</td>
|
||||
<td class="right">
|
||||
<td class="right ratio">
|
||||
<div>
|
||||
<input
|
||||
value={compounded.value.t3Syn}
|
||||
@@ -143,8 +142,8 @@ export default defineComponent({
|
||||
step="1"
|
||||
type="number"
|
||||
/>
|
||||
</div>{" "}
|
||||
:{" "}
|
||||
</div>
|
||||
<span class="separator"/>
|
||||
<div>
|
||||
<input
|
||||
value={compounded.value.t4Syn}
|
||||
@@ -169,7 +168,7 @@ export default defineComponent({
|
||||
<p>
|
||||
<ul>
|
||||
<li>
|
||||
1st November 2024: Migrated to new web framework and fixed some buggy input.
|
||||
1st November 2024: Migrated to new web framework and fixed some buggy input/ugly styling.
|
||||
</li>
|
||||
<li>
|
||||
13th March 2024: Removed the synthetic/pure distinction as it was confusing and
|
||||
|
||||
@@ -64,8 +64,9 @@ export default defineComponent({
|
||||
{rpArticles.value && rpArticles.value.map((_) => (
|
||||
<li>
|
||||
<RouterLink to={{ name: "GEDeutschArticle", params: { articleName: _.slug } }}>
|
||||
{_.name}
|
||||
{_.title}
|
||||
</RouterLink>
|
||||
{_.tags?.map(tag => <span class="tag">{tag}</span>)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { createTextVNode, defineComponent, h, inject, onServerPrefetch, ref, type VNode, watchEffect } from "vue";
|
||||
import { createTextVNode, computed, defineComponent, h, inject, onServerPrefetch, ref, type VNode, watchEffect } from "vue";
|
||||
import { RouterLink } from "vue-router";
|
||||
import useAsyncState from "@/useAsyncState.ts";
|
||||
import useHead from "@/useHead.ts";
|
||||
import DJEmail from "@/DJEmail.tsx";
|
||||
import getDJAPI from "@/api.ts";
|
||||
|
||||
export default defineComponent({
|
||||
name: "ge-deutsch-article",
|
||||
@@ -23,25 +25,32 @@ export default defineComponent({
|
||||
(innerHTML: string) => Object.assign(document.createElement("div"), { innerHTML }),
|
||||
);
|
||||
|
||||
const title = ref("");
|
||||
|
||||
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;
|
||||
},
|
||||
);
|
||||
|
||||
const {
|
||||
result: articleData,
|
||||
stateIsReady: articleDataReady,
|
||||
} = useAsyncState('article-data', ({hostUrl}) => getDJAPI(hostUrl, '/rp-articles'));
|
||||
|
||||
const articleMetadata = computed(() => articleData.value?.find(_ => _.slug === props.articleName));
|
||||
|
||||
const title = computed(() => {
|
||||
return articleContent.value?.split('<h1 lang="de">')[1].split("</h1>")[0] ?? 'Artikel';
|
||||
});
|
||||
|
||||
useHead({ title });
|
||||
|
||||
onServerPrefetch(() =>
|
||||
new Promise<void>((res) => {
|
||||
watchEffect(() => {
|
||||
if (title.value !== "") {
|
||||
console.log("resolve", title.value);
|
||||
res();
|
||||
}
|
||||
});
|
||||
@@ -59,7 +68,7 @@ export default defineComponent({
|
||||
children.unshift(h("button", {
|
||||
class: "swap",
|
||||
onClick: (e) => {
|
||||
e.target.parentElement.classList.toggle("swap");
|
||||
(e.target as HTMLButtonElement).parentElement?.classList.toggle("swap");
|
||||
},
|
||||
}, "↻"));
|
||||
}
|
||||
@@ -71,7 +80,11 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
return h((node as Element).tagName, attrs, children);
|
||||
if (el.tagName === "H1") {
|
||||
return h("header", attrs, h("h1", {}, children));
|
||||
} else {
|
||||
return h((node as Element).tagName, attrs, children);
|
||||
}
|
||||
} else {
|
||||
return createTextVNode(node.textContent ?? "");
|
||||
}
|
||||
@@ -85,7 +98,8 @@ export default defineComponent({
|
||||
return <div>Artikel lädt...</div>;
|
||||
}
|
||||
|
||||
await stateIsReady;
|
||||
await Promise.all([stateIsReady, articleDataReady]);
|
||||
console.log(articleMetadata.value);
|
||||
|
||||
return () => (
|
||||
<div class="ge-article">
|
||||
@@ -95,6 +109,12 @@ export default defineComponent({
|
||||
Sprache auf <span>{currentLang.value === "en" ? "Deutsch" : "Englisch"}</span> umschalten
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-slab">
|
||||
Bei dem untenstehenden Artikel handelt es sich um eine hobbymäßige, amateurhafte Übersetzung des
|
||||
Artikels „{ title.value }“ von Ray Peat. Bei Ungenauigkeiten oder Fehlübersetzungen freue ich mich über <DJEmail>eine Mail</DJEmail>!
|
||||
</p>
|
||||
{ articleMetadata.value?.tags?.includes('in-arbeit') && <h5 class="baustelle">🚧 Bitte beachte, dass diese Übersetzung noch in Arbeit und darum nicht fertig ist! 🚧</h5> }
|
||||
<hr />
|
||||
<article class={`lang-${currentLang.value}`}>
|
||||
<ArticleContentTransformed />
|
||||
</article>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { RouterLink } from "vue-router";
|
||||
import useHead from "@/useHead.ts";
|
||||
import DJTooltip from "@/DJTooltip.tsx";
|
||||
|
||||
export default {
|
||||
name: "ge-main",
|
||||
@@ -20,16 +21,14 @@ export default {
|
||||
<h2>Links</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<RouterLink to={{ name: "GECalculator" }}>Thyroid Calculator</RouterLink>
|
||||
<span style="display: none" class="tooltip">
|
||||
Convert to and from grains, set ratios, etc.
|
||||
</span>
|
||||
<DJTooltip tooltip="Convert to and from grains, set ratios, etc.">
|
||||
<RouterLink to={{ name: "GECalculator" }}>Thyroid Calculator</RouterLink>
|
||||
</DJTooltip>
|
||||
</li>
|
||||
<li>
|
||||
<RouterLink to={{ name: "GEDeutsch" }}>Ray Peat Articles in German</RouterLink>
|
||||
<span style="display: none" class="tooltip">
|
||||
A selection of articles by Ray that I have translated in my spare time into German.
|
||||
</span>
|
||||
<DJTooltip tooltip="A selection of articles by Ray that I have translated in my spare time into German.">
|
||||
<RouterLink to={{ name: "GEDeutsch" }}>Ray Peat Articles in German</RouterLink>
|
||||
</DJTooltip>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineComponent, Suspense, type VNode } from "vue";
|
||||
import { defineComponent, ref, Suspense, type VNode } from "vue";
|
||||
import { type RouteRecordRaw, RouterLink, RouterView, useRoute } from "vue-router";
|
||||
import GEMain from "@/generative-energy/GEMain.tsx";
|
||||
import DJEmail from "@/DJEmail.tsx";
|
||||
@@ -6,6 +6,7 @@ import GEDeutsch from "@/generative-energy/GEDeutsch.tsx";
|
||||
import GEDeutschArticle from "@/generative-energy/GEDeutschArticle.tsx";
|
||||
import GECalculator from "@/generative-energy/GECalculator.tsx";
|
||||
import DJDonate from "@/DJDonate.tsx";
|
||||
import { setupTooltip } from "@/DJTooltip.tsx";
|
||||
|
||||
export const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
@@ -41,8 +42,11 @@ export default defineComponent({
|
||||
name: "ge-root",
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const carrier = ref<HTMLDivElement | null>(null);
|
||||
setupTooltip({ carrier });
|
||||
return () => (
|
||||
<>
|
||||
<div ref={carrier} class="tooltip-carrier" />
|
||||
<main>
|
||||
<RouterLink class={"home-btn" + (route.name === "GEMain" ? " hide" : "")} to={{ name: "GEMain" }}>
|
||||
Generative Energy Home
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { createSSRApp } from "vue";
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import GERoot, { routes } from "@/generative-energy/GERoot.tsx";
|
||||
import { cssRegistry } from "@/util.ts";
|
||||
|
||||
createSSRApp(GERoot)
|
||||
.provide(cssRegistry, new Set())
|
||||
.use(createRouter({
|
||||
routes,
|
||||
history: createWebHistory("/generative-energy"),
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { createSSRApp } from "vue";
|
||||
import DJHomeRoot from "@/home/DJHomeRoot.tsx";
|
||||
import { cssRegistry } from "@/util.ts";
|
||||
|
||||
createSSRApp(DJHomeRoot).mount("#app-root");
|
||||
createSSRApp(DJHomeRoot)
|
||||
.provide(cssRegistry, new Set())
|
||||
.mount("#app-root");
|
||||
|
||||
@@ -5,6 +5,7 @@ export type DJSSRContext = {
|
||||
title: MaybeRefOrGetter<string>;
|
||||
};
|
||||
registry: Record<string, unknown>;
|
||||
styles: Record<string, string>;
|
||||
};
|
||||
|
||||
export default function useDJSSRContext() {
|
||||
|
||||
23
app/util.ts
23
app/util.ts
@@ -1,3 +1,6 @@
|
||||
import { type InjectionKey, inject } from 'vue';
|
||||
import useDJSSRContext from "@/useDJSSRContext.ts";
|
||||
|
||||
export function gid(id: string, doc: (Document | ShadowRoot) | undefined) {
|
||||
return ((doc ?? document).getElementById(id));
|
||||
}
|
||||
@@ -37,9 +40,23 @@ export function css(strs: TemplateStringsArray, ...vals: string[]) {
|
||||
for (let i = 1; i < strs.length; i++) {
|
||||
result += vals[i] + strs[i];
|
||||
}
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replaceSync(result);
|
||||
return sheet;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
export const cssRegistry = Symbol('css-registry') as InjectionKey<Set<string>>;
|
||||
export function addCSS(key: string, css: string) {
|
||||
const context = useDJSSRContext();
|
||||
if (context && !context.styles[key]) {
|
||||
context.styles[key] = css;
|
||||
} else {
|
||||
const registry = inject(cssRegistry);
|
||||
if (!registry?.has(key)) {
|
||||
const stylesheet = new CSSStyleSheet();
|
||||
stylesheet.replace(css);
|
||||
document.adoptedStyleSheets.push(stylesheet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user