Files
web/src/pages/api/giscus-theme.ts

277 lines
9.6 KiB
TypeScript

import type { APIRoute } from "astro";
import { THEMES, DEFAULT_THEME_ID } from "@/lib/themes";
function rgbToHex(rgb: string): string {
return "#" + rgb.split(" ").map(n => parseInt(n).toString(16).padStart(2, "0")).join("");
}
function rgbToRgba(rgb: string, alpha: number): string {
return `rgba(${rgb.replaceAll(" ", ", ")}, ${alpha})`;
}
export const GET: APIRoute = ({ url }) => {
const themeId = url.searchParams.get("theme") || DEFAULT_THEME_ID;
const theme = THEMES[themeId];
if (!theme) {
return new Response("Unknown theme", { status: 404 });
}
const c = theme.colors;
const isLight = theme.type === "light";
const fg = rgbToHex(c.foreground);
const fgMuted = rgbToRgba(c.foreground, 0.6);
const fgSubtle = rgbToRgba(c.foreground, 0.4);
const blue = rgbToHex(c.blue);
const blueBright = rgbToHex(c.blueBright);
const green = rgbToHex(c.green);
const yellow = rgbToHex(c.yellow);
const red = rgbToHex(c.red);
const purple = rgbToHex(c.purple);
const orange = rgbToHex(c.orange);
const surface = rgbToHex(c.surface);
const surfaceAlpha = rgbToRgba(c.surface, 0.3);
const surfaceBorder = rgbToRgba(c.surface, 0.5);
const surfaceHover = rgbToRgba(c.surface, 0.6);
const bgTransparent = isLight ? rgbToRgba(c.foreground, 0.06) : rgbToRgba(c.foreground, 0.08);
const bgSubtle = isLight ? rgbToRgba(c.foreground, 0.04) : rgbToRgba(c.foreground, 0.05);
const css = `
main {
--color-prettylights-syntax-comment: ${fgSubtle};
--color-prettylights-syntax-constant: ${blueBright};
--color-prettylights-syntax-entity: ${purple};
--color-prettylights-syntax-storage-modifier-import: ${fg};
--color-prettylights-syntax-entity-tag: ${green};
--color-prettylights-syntax-keyword: ${red};
--color-prettylights-syntax-string: ${blueBright};
--color-prettylights-syntax-variable: ${orange};
--color-prettylights-syntax-brackethighlighter-unmatched: ${red};
--color-prettylights-syntax-invalid-illegal-text: ${fg};
--color-prettylights-syntax-invalid-illegal-bg: ${red};
--color-prettylights-syntax-carriage-return-text: ${fg};
--color-prettylights-syntax-carriage-return-bg: ${red};
--color-prettylights-syntax-string-regexp: ${green};
--color-prettylights-syntax-markup-list: ${yellow};
--color-prettylights-syntax-markup-heading: ${blueBright};
--color-prettylights-syntax-markup-italic: ${fg};
--color-prettylights-syntax-markup-bold: ${orange};
--color-prettylights-syntax-markup-deleted-text: ${red};
--color-prettylights-syntax-markup-deleted-bg: transparent;
--color-prettylights-syntax-markup-inserted-text: ${green};
--color-prettylights-syntax-markup-inserted-bg: transparent;
--color-prettylights-syntax-markup-changed-text: ${yellow};
--color-prettylights-syntax-markup-changed-bg: transparent;
--color-prettylights-syntax-markup-ignored-text: ${fg};
--color-prettylights-syntax-markup-ignored-bg: transparent;
--color-prettylights-syntax-meta-diff-range: ${purple};
--color-prettylights-syntax-brackethighlighter-angle: ${fgSubtle};
--color-prettylights-syntax-sublimelinter-gutter-mark: ${fgSubtle};
--color-prettylights-syntax-constant-other-reference-link: ${blueBright};
--color-btn-text: ${fg};
--color-btn-bg: ${bgTransparent};
--color-btn-border: ${surfaceBorder};
--color-btn-shadow: 0 0 transparent;
--color-btn-inset-shadow: 0 0 transparent;
--color-btn-hover-bg: ${surfaceAlpha};
--color-btn-hover-border: ${surfaceHover};
--color-btn-active-bg: ${bgSubtle};
--color-btn-active-border: ${surfaceHover};
--color-btn-selected-bg: ${bgTransparent};
--color-btn-primary-text: ${fg};
--color-btn-primary-bg: ${blue};
--color-btn-primary-border: transparent;
--color-btn-primary-shadow: 0 0 transparent;
--color-btn-primary-inset-shadow: 0 0 transparent;
--color-btn-primary-hover-bg: ${blueBright};
--color-btn-primary-hover-border: transparent;
--color-btn-primary-selected-bg: ${blue};
--color-btn-primary-selected-shadow: 0 0 transparent;
--color-btn-primary-disabled-text: ${fgMuted};
--color-btn-primary-disabled-bg: ${rgbToRgba(c.blue, 0.6)};
--color-btn-primary-disabled-border: transparent;
--color-action-list-item-default-hover-bg: ${surfaceAlpha};
--color-segmented-control-bg: ${surfaceAlpha};
--color-segmented-control-button-bg: ${bgTransparent};
--color-segmented-control-button-selected-border: ${surfaceBorder};
--color-fg-default: ${fg};
--color-fg-muted: ${fgMuted};
--color-fg-subtle: ${fgSubtle};
--color-canvas-default: transparent;
--color-canvas-overlay: ${bgTransparent};
--color-canvas-inset: ${bgSubtle};
--color-canvas-subtle: ${bgSubtle};
--color-border-default: ${surfaceBorder};
--color-border-muted: ${surfaceAlpha};
--color-neutral-muted: ${rgbToRgba(c.surface, 0.25)};
--color-accent-fg: ${blueBright};
--color-accent-emphasis: ${blue};
--color-accent-muted: ${rgbToRgba(c.blue, 0.4)};
--color-accent-subtle: ${rgbToRgba(c.blue, 0.1)};
--color-success-fg: ${green};
--color-attention-fg: ${yellow};
--color-attention-muted: ${rgbToRgba(c.yellow, 0.4)};
--color-attention-subtle: ${rgbToRgba(c.yellow, 0.15)};
--color-danger-fg: ${red};
--color-danger-muted: ${rgbToRgba(c.red, 0.4)};
--color-danger-subtle: ${rgbToRgba(c.red, 0.1)};
--color-primer-shadow-inset: 0 0 transparent;
--color-scale-gray-7: ${surface};
--color-scale-blue-8: ${blue};
--color-social-reaction-bg-hover: ${surfaceAlpha};
--color-social-reaction-bg-reacted-hover: ${rgbToRgba(c.blue, 0.3)};
}
main .pagination-loader-container {
background-image: url(https://github.com/images/modules/pulls/progressive-disclosure-line${isLight ? "" : "-dark"}.svg);
}
.gsc-reactions-count { display: none; }
.gsc-timeline { flex-direction: column-reverse; }
.gsc-header {
padding-bottom: 1rem;
font-family: "Comic Code", monospace;
border-bottom: none;
}
.gsc-comments > .gsc-header { order: 1; }
.gsc-comments > .gsc-comment-box {
margin-bottom: 1rem;
order: 2;
font-family: "Comic Code", monospace;
background-color: ${bgTransparent};
border-radius: 0.5rem;
border: 1px solid ${surfaceBorder};
}
.gsc-comments > .gsc-timeline { order: 3; }
.gsc-homepage-bg { background-color: transparent; }
main .gsc-loading-image {
background-image: url(https://github.githubassets.com/images/mona-loading-${isLight ? "default" : "dimmed"}.gif);
}
.gsc-comment {
border: 1px solid ${surfaceBorder};
border-radius: 0.5rem;
margin-bottom: 1rem;
background-color: ${bgTransparent};
transition: border-color 0.2s ease;
}
.gsc-comment-header {
background-color: ${bgSubtle};
padding: 0.75rem;
border-bottom: 1px solid ${rgbToRgba(c.surface, 0.2)};
font-family: "Comic Code", monospace;
}
.gsc-comment-content {
padding: 1rem;
font-family: "Comic Code", monospace;
}
.gsc-comment-author { color: var(--color-fg-default); font-weight: 600; }
.gsc-comment-author-avatar img { border-radius: 50%; }
.gsc-comment-reactions { border-top: none; padding-top: 0.5rem; }
.gsc-reply-box {
background-color: ${bgTransparent};
border-radius: 0.5rem;
margin-top: 0.5rem;
margin-left: 1rem;
font-family: "Comic Code", monospace;
border: 1px solid ${rgbToRgba(c.surface, 0.25)};
}
.gsc-comment-box-textarea {
background-color: ${bgSubtle};
border: 1px solid ${surfaceBorder};
border-radius: 0.5rem;
color: var(--color-fg-default);
font-family: "Comic Code", monospace;
padding: 0.75rem;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.gsc-comment-box-textarea:focus {
border-color: ${blueBright};
box-shadow: 0 0 0 2px ${rgbToRgba(c.blue, 0.2)};
outline: none;
}
.gsc-comment-box-buttons button {
font-family: "Comic Code", monospace;
border-radius: 0.5rem;
transition: background-color 0.2s ease, border-color 0.2s ease;
}
.gsc-comment pre {
background-color: ${bgSubtle};
border-radius: 0.5rem;
padding: 1rem;
overflow-x: auto;
border: 1px solid ${rgbToRgba(c.surface, 0.25)};
}
.gsc-comment code {
font-family: "Comic Code", monospace;
background-color: ${bgSubtle};
color: ${purple};
padding: 0.2em 0.4em;
border-radius: 0.25rem;
}
.gsc-comment:hover { border-color: ${surfaceHover}; }
.gsc-social-reaction-summary-item:hover { background-color: ${surfaceAlpha}; }
.gsc-timeline::-webkit-scrollbar { width: 8px; height: 8px; }
.gsc-timeline::-webkit-scrollbar-track { background: transparent; border-radius: 4px; }
.gsc-timeline::-webkit-scrollbar-thumb { background: ${surfaceBorder}; border-radius: 4px; }
.gsc-timeline::-webkit-scrollbar-thumb:hover { background: ${surface}; }
.gsc-comment-footer, .gsc-comment-footer-separator,
.gsc-reactions-button, .gsc-social-reaction-summary-item:not(:hover) { border: none; }
.gsc-upvote svg { fill: ${blueBright}; }
.gsc-downvote svg { fill: ${red}; }
.gsc-comment-box, .gsc-comment, .gsc-comment-reactions, button, .gsc-reply-box {
transition: all 0.2s ease-in-out;
}
.gsc-main { border: none !important; }
.gsc-left-header { background-color: transparent !important; }
.gsc-right-header { background-color: transparent !important; }
.gsc-header-status { background-color: transparent !important; }
.gsc-comment-box, .gsc-comment-box-md-toolbar, .gsc-comment-box-buttons { border: none !important; }
.gsc-comment-box-md-toolbar-item { color: ${blueBright} !important; }
.gsc-comment-box-md-toolbar {
background-color: ${bgSubtle} !important;
padding: 0.5rem !important;
}
.gsc-comments .gsc-powered-by { display: none !important; }
.gsc-comments footer { display: none !important; }
.gsc-comments .gsc-powered-by a { visibility: hidden !important; }
`;
return new Response(css, {
headers: {
"Content-Type": "text/css",
"Cache-Control": "public, max-age=3600",
"Access-Control-Allow-Origin": "*",
},
});
};