Compare commits

..

2 Commits

Author SHA1 Message Date
Julien Calixte
d50adc72e9 refactor(downloadFont): handle generic families and multi-family strings
Strips generic CSS families (serif, monospace, etc.) before building
the font API URL, and correctly parses comma-separated font stacks.
2026-04-27 10:12:12 +02:00
Julien Calixte
78de5e280f feat: show GitHub sign-in when repo is not accessible
Adds a message + sign-in button in FluxNote when the readme resolves
to null (private/unauthorized repo), and on the SpaceCowboy 404 page.
2026-04-27 10:12:09 +02:00
3 changed files with 52 additions and 20 deletions

View File

@@ -2,6 +2,7 @@
import { computed, nextTick, onMounted, onUnmounted, toRefs, watch } from "vue" import { computed, nextTick, onMounted, onUnmounted, toRefs, watch } from "vue"
import HeaderNote from "@/components/HeaderNote.vue" import HeaderNote from "@/components/HeaderNote.vue"
import SignInGithub from "@/components/SignInGithub.vue"
import SkeletonLoader from "@/components/SkeletonLoader.vue" import SkeletonLoader from "@/components/SkeletonLoader.vue"
import StackedNote from "@/components/StackedNote.vue" import StackedNote from "@/components/StackedNote.vue"
import { useLinks } from "@/hooks/useLinks.hook" import { useLinks } from "@/hooks/useLinks.hook"
@@ -102,6 +103,10 @@ onUnmounted(() => {
</div> </div>
<slot /> <slot />
<skeleton-loader v-if="isLoading" /> <skeleton-loader v-if="isLoading" />
<div v-else-if="withContent && !hasContent" class="repo-not-found">
<p>This repository is not accessible.</p>
<sign-in-github />
</div>
<p <p
v-else-if="withContent && hasContent" v-else-if="withContent && hasContent"
class="note-display" class="note-display"
@@ -189,6 +194,15 @@ $header-height: 40px;
} }
} }
.repo-not-found {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
padding: 2rem 0;
color: var(--color-base-content);
}
.note-display { .note-display {
padding-bottom: 2rem; padding-bottom: 2rem;
} }

View File

@@ -1,33 +1,48 @@
import FontFaceObserver from "fontfaceobserver" import FontFaceObserver from "fontfaceobserver"
const assembleFontLink = (font: string) => { const GENERIC_FAMILIES = new Set([
return `https://api.fonts.coollabs.io/css2?display=swap&family=${font "serif", "sans-serif", "monospace", "cursive", "fantasy",
.replaceAll(",", "&family=") "system-ui", "ui-serif", "ui-sans-serif", "ui-monospace", "ui-rounded",
.replaceAll(" ", "+")}` ])
const parseWebFontFamilies = (font: string): string[] =>
font
.split(",")
.map(f => f.trim().replace(/^["']|["']$/g, ""))
.filter(f => f && !GENERIC_FAMILIES.has(f))
const assembleFontLink = (families: string[]): string | null => {
if (families.length === 0) return null
return `https://api.fonts.coollabs.io/css2?display=swap&${
families.map(f => `family=${f.replaceAll(" ", "+")}`).join("&")
}`
} }
export const downloadFont = async ( export const downloadFont = async (
font: string, font: string,
cssVar = "--font-family" cssVar = "--font-family"
): Promise<void> => { ): Promise<void> => {
const href = assembleFontLink(font) const families = parseWebFontFamilies(font)
const href = assembleFontLink(families)
// check if the href already exists if (href) {
const existingLink = document.querySelector(`link[href="${href}"]`) const alreadyLoaded = Array.from(
document.head.querySelectorAll<HTMLLinkElement>('link[rel="stylesheet"]')
).some(link => link.href === href)
if (!existingLink) { if (!alreadyLoaded) {
const link = document.createElement("link") const link = document.createElement("link")
link.href = href link.href = href
link.rel = "stylesheet" link.rel = "stylesheet"
document.head.appendChild(link) document.head.appendChild(link)
} }
try { try {
await new FontFaceObserver(font).load() await new FontFaceObserver(families[0]).load()
} catch {
document.documentElement.style.setProperty(cssVar, font)
} catch (error) {
console.warn("error when loading font") console.warn("error when loading font")
} }
}
document.documentElement.style.setProperty(cssVar, font)
} }

View File

@@ -1,4 +1,6 @@
<script lang="ts" setup></script> <script lang="ts" setup>
import SignInGithub from "@/components/SignInGithub.vue"
</script>
<template> <template>
<main class="space-cowboy content"> <main class="space-cowboy content">
@@ -43,6 +45,7 @@
<router-link class="button is-links" :to="{ name: 'Home' }" <router-link class="button is-links" :to="{ name: 'Home' }"
>return to homepage</router-link >return to homepage</router-link
> >
<sign-in-github />
</main> </main>
</template> </template>