Convert styling to Tailwind (#15)

* Initialize tailwind

* Convert styling to Tailwind

* Add console output for CSS build

* Allow reading the feeds from an environment variable

* Change link styling and no-script time format

* Fix ellipses
This commit is contained in:
Carter McBride 2024-07-17 12:01:36 -06:00 committed by GitHub
parent 58d8f68825
commit 2932a6276e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 345 additions and 216 deletions

2
.gitignore vendored
View file

@ -1,4 +1,6 @@
node_modules/* node_modules/*
public/index.html public/index.html
public/styles.css
dist/* dist/*
.DS_Store .DS_Store
configs/feeds.json

BIN
bun.lockb

Binary file not shown.

View file

@ -1,100 +0,0 @@
{
"Comics": [
"http://www.catanacomics.com/rss",
"http://feeds.feedburner.com/InvisibleBread",
"https://hejibits.com/rss#_=_",
"http://www.hrwiki.org/wiki/Special:Updates",
"http://rockpapercynic.tumblr.com/rss"
],
"Podcasts & Videos": [
"https://lilyandsam.show/feed",
"https://www.youtube.com/feeds/videos.xml?channel_id=UC3g-w83Cb5pEAu5UmRrge-A",
"https://www.youtube.com/feeds/videos.xml?channel_id=UCakAg8hC_RFJm4RI3DlD7SA",
"https://www.youtube.com/feeds/videos.xml?channel_id=UCHZOwvEh9FAG95RO3PWhe5g",
"https://www.youtube.com/feeds/videos.xml?channel_id=UCvVsD2hFZRgKNH7x5Q1wwug",
"https://www.youtube.com/feeds/videos.xml?channel_id=UCDq5v10l4wkV5-ZBIJJFbzQ",
"https://www.youtube.com/feeds/videos.xml?channel_id=UCMkbjxvwur30YrFWw8kpSaw",
"https://www.youtube.com/feeds/videos.xml?channel_id=UCSuT9FSddzI6W5Bij9XwtmA",
"https://www.youtube.com/feeds/videos.xml?channel_id=UCqqJQ_cXSat0KIAVfIfKkVA",
"https://www.youtube.com/feeds/videos.xml?channel_id=UCuvSqzfO_LV_QzHdmEj84SQ",
"https://www.youtube.com/feeds/videos.xml?channel_id=UCSdma21fnJzgmPodhC9SJ3g",
"https://www.youtube.com/feeds/videos.xml?channel_id=UCj1VqrHhDte54oLgPG4xpuQ",
"https://www.youtube.com/feeds/videos.xml?channel_id=UCy0tKL1T7wFoYcxCe0xjN6Q",
"https://www.youtube.com/feeds/videos.xml?channel_id=UCsvn_Po0SmunchJYOWpOxMg"
],
"Friends and Family": [
"https://www.goodreads.com/review/list_rss/132710826?shelf=read",
"https://joekhoury.blog/feed/",
"https://mastodon.social/users/samwarnick.rss"
],
"Games": [
"https://www.nomanssky.com/news/feed/",
"https://www.lexaloffle.com/bbs/feed.php?uid=1",
"https://www.factorio.com/blog/rss",
"https://kill-the-newsletter.com/feeds/pghhn8aaf264tukg.xml",
"http://www.suppermariobroth.com/rss",
"http://unknownworlds.com/subnautica/feed/",
"https://store.steampowered.com/feeds/news/app/1675200/?cc=US&l=english"
],
"Finance": [
"http://feeds.feedburner.com/MrMoneyMustache",
"http://feeds.feedburner.com/DoctorOfCredit",
"https://kill-the-newsletter.com/feeds/tgor1vrwcf3f0uyo.xml",
"https://kill-the-newsletter.com/feeds/5q4gs79dfh32yr3h.xml"
],
"News": [
"http://www.economist.com/rss/the_world_this_week_rss.xml",
"https://newsroom.churchofjesuschrist.org/rss",
"http://feeds.feedburner.com/LdsChurchGrowth",
"https://www.sltrib.com/arc/outboundfeeds/news/?outputType=xml",
"https://www.ksl.com/rss/news/news_utah",
"https://www.readtangle.com/posts/rss/"
],
"Parenting": [
"https://technosapiens.substack.com/feed",
"https://parentdata.org/feed/"
],
"Fashion": [
"http://www.heddels.com/feed/",
"http://putthison.com/rss",
"https://articlesofinterest.substack.com/feed",
"https://dappered.com/feed/",
"https://dieworkwear.com/feed/",
"http://fromsqualortoballer.com/rss",
"https://fabricateurialist.substack.com/feed",
"https://www.menswearmusings.com/feed/",
"https://www.permanentstyle.com/feed"
],
"Products": [
"https://jellyfin.org/index.xml",
"https://gitlab.com/CalcProgrammer1/OpenRGB/-/tags?format=atom",
"http://feeds.feedburner.com/psblog",
"https://matrix.org/blog/feed/",
"https://brave.com/feed/",
"https://bitwarden.com/blog/feed.xml"
],
"Humor": [
"https://kill-the-newsletter.com/feeds/d90ng280lhh3p2nq.xml",
"https://aiweirdness.com/rss",
"http://mcmansionhell.tumblr.com/rss"
],
"Other": [
"https://kill-the-newsletter.com/feeds/400aiwxy5ox6ao0d.xml",
"http://brandonsanderson.com/feed/",
"https://kill-the-newsletter.com/feeds/j3c4wngg2hpjmdt8.xml",
"https://astralcodexten.substack.com/feed/"
],
"Tech News": [
"https://samwarnick.com/feed.rss",
"http://feeds.feedburner.com/CssTricks",
"http://chriscoyier.net/feed/",
"https://jenniferdaniel.substack.com/feed/",
"http://www.gamingonlinux.com/article_rss.php",
"http://www.theverge.com/rss/full.xml",
"https://hnrss.org/frontpage?points=70"
],
"Emulation": [
"http://melonds.kuribo64.net/rss.php",
"https://dolphin-emu.org/blog/feeds/"
]
}

View file

@ -7,7 +7,7 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Carter's RSS Feeds</title> <title>Carter's RSS Feeds</title>
<link rel="icon" href="news-emoji.svg" sizes="any" type="image/svg+xml"> <link rel="icon" href="news-emoji.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="styles.css" />
<link rel="manifest" href="manifest.json" /> <link rel="manifest" href="manifest.json" />
<script type="module" defer> <script type="module" defer>
/** /**
@ -98,35 +98,45 @@
</script> </script>
</head> </head>
<body> <body class="font-system bg-arc-background text-base m-4">
<header> <header class="text-2xl text-arc-title">
<h1>📰 Carter's RSS Feeds</h1> <h1>📰 Carter's RSS Feeds</h1>
</header> </header>
<main> <main class="grid gap-4 grid-cols-[repeat(auto-fill,_minmax(300px,_1fr))] mt-2">
{% for group, feeds in data %} {% for group, feeds in data %}
<section> <section class="">
<h2>{{ group }}</h2> <h2 class="text-xl">{{ group }}</h2>
{% for feed in feeds %} {% for feed in feeds %}
<details> <details class="group">
<summary> <summary class="cursor-pointer p-2 rounded-xl mt-1 transition-colors group-has-[.has-recent]:border-2 group-has-[.has-recent]:border-arc-title hover:bg-arc-hover flex flex-row items-center">
<span class="feed-title">{{ feed.title }}</span> {% if feed.hasRecent %}
<span class="feed-url" title="{{feed.feed}}">({{ feed.feed }})</span> <div class="text-xl mr-2" aria-label="Feed has recent items">✳︎</div>
{% endif %}
<div class="w-full">
<div>{{ feed.title }}</div>
<div class="text-sm whitespace-nowrap text-ellipsis w-11/12 overflow-hidden text-arc-subtitle" title="{{feed.feed}}">({{ feed.feed }})</div>
</div>
</summary> </summary>
<ul> <ul class="max-h-64 overflow-y-auto list-none m-0">
{% for item in feed.items %} {% for item in feed.items %}
<li class="{% if item.isRecent %}has-recent{% endif %}"> <li class="{% if item.isRecent %}has-recent {% endif %} flex flex-row items-center p-2 rounded-xl mt-1 transition-colors hover:bg-arc-hover">
{% if item.isRecent %}
<div class="text-xl mr-2" aria-label="Item is recent">✳︎</div>
{% endif %}
<div> <div>
<a class="article-title" href="{{ item.link }}" target="_blank" rel="noopener norefferer nofollow">{{ <div>
<a class="no-underline hover:text-inherit" href="{{ item.link }}" target="_blank" rel="noopener norefferer nofollow">{{
item.title | safe}}</a> item.title | safe}}</a>
</div> </div>
<div class="article-timestamp"> <div class="text-sm text-arc-subtitle">
<relative-time data-time="{{item.timestamp}}">{{ item.timestamp | relative}}</relative-time> <relative-time data-time="{{item.timestamp}}">{{ item.timestamp | formatDateTime}}</relative-time>
</div> </div>
{% if yazzyUrl %} {% if yazzyUrl %}
<div class="article-links"> <div class="text-sm text-arc-subtitle">
<a href="{{ yazzyUrl }}/{{ item.link }}" target="_blank" rel="noreferrer noopener">yazzy</a> <a href="{{ yazzyUrl }}/{{ item.link }}" target="_blank" rel="noreferrer noopener">yazzy</a>
</div> </div>
{% endif %} {% endif %}
</div>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
@ -136,17 +146,17 @@
{% endfor %} {% endfor %}
</main> </main>
{% if errors | length > 0 %} {% if errors | length > 0 %}
<h2>Errors</h2> <h2 class="text-xl">Errors</h2>
<p>There were errors trying to parse these feeds:</p> <p>There were errors trying to parse these feeds:</p>
<ul class="errors"> <ul class="errors">
{% for error in errors %} {% for error in errors %}
<li>{{ error }}</li> <li class="break-all">{{ error }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
<footer> <footer>
<hr> <hr>
<p>Last updated <relative-time data-time="{{ now }}">{{ now | relative}}</relative-time>.</p> <p>Last updated <relative-time data-time="{{ now }}">{{ now | formatDateTime}}</relative-time>.</p>
<p> <p>
<a href="https://github.com/carterworks/rss-reader">View on GitHub</a> <a href="https://github.com/carterworks/rss-reader">View on GitHub</a>
</p> </p>

View file

@ -7,8 +7,9 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"clean": "rm -rf dist", "clean": "rm -rf dist",
"build": "bun src/index.ts", "build": "NODE_ENV=production bun src/index.ts",
"check": "biome check --write ./{src,config,public} ./*.json --no-errors-on-unmatched" "check": "biome check --write ./{src,config,public} ./*.{json,js} --no-errors-on-unmatched",
"dev": "bun src/index.ts"
}, },
"author": { "author": {
"name": "George Mandis", "name": "George Mandis",
@ -36,6 +37,7 @@
"@types/bun": "latest", "@types/bun": "latest",
"@types/nunjucks": "^3.2.2", "@types/nunjucks": "^3.2.2",
"@types/xml2js": "^0.4.11", "@types/xml2js": "^0.4.11",
"tailwindcss": "^3.4.6",
"tslib": "^2.5.3", "tslib": "^2.5.3",
"typescript": "^5.1.3", "typescript": "^5.1.3",
"typescript-eslint": "^7.13.1" "typescript-eslint": "^7.13.1"

View file

@ -1,80 +0,0 @@
:root {
--color-bg: oklch(97.1% 0.024 88.23);
--color-hover: oklch(94.48% 0.024 88.23);
--color-text: oklch(24.74% 0.024 88.23);
--color-new: oklch(94.48% 0.024 38.23);
}
body {
font-family: system-ui;
font-size: 18px;
background: var(--color-bg);
color: var(--color-text);
}
main {
display: grid;
gap: 1em;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
section ul {
max-height: 250px;
overflow-y: auto;
}
.inline-icon {
height: 1em;
vertical-align: text-bottom;
}
summary {
cursor: pointer;
text-overflow: ellipsis;
}
summary,
details li {
padding: 0.5em;
border-radius: 12px;
margin-block-start: 4px;
transition: background cubic-bezier(0.39, 0.575, 0.565, 1) 0.2s;
}
summary:hover,
details li:hover {
background: var(--color-hover)
}
details:has(li.has-recent) {
summary,
li.has-recent {
background: var(--color-new);
}
}
.errors li {
word-break: break-all;
}
.feed-url {
color: #aaa;
white-space: nowrap;
display: inline-block;
text-overflow: ellipsis;
width: 100%;
overflow: hidden;
}
.article-timestamp,
.feed-url,
.article-links {
font-size: 0.75em;
}
details ul {
list-style-type: none;
margin: 0;
}

3
public/styles.input.css Normal file
View file

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View file

@ -18,6 +18,7 @@ import Parser from "rss-parser";
import type { FeedItem, Feeds } from "./@types/bubo"; import type { FeedItem, Feeds } from "./@types/bubo";
import { render } from "./renderer.js"; import { render } from "./renderer.js";
import { import {
buildCSS,
getBuboInfo, getBuboInfo,
getFeedList, getFeedList,
getLink, getLink,
@ -26,9 +27,21 @@ import {
parseFeed, parseFeed,
} from "./utilities.js"; } from "./utilities.js";
const cssInput = "./public/styles.input.css";
const cssOutput = "./public/styles.css";
const minifyCss = process.env.NODE_ENV === "production";
await buildCSS(minifyCss, cssInput, cssOutput);
const buboInfo = await getBuboInfo(); const buboInfo = await getBuboInfo();
const parser = new Parser(); const parser = new Parser();
const feedList = await getFeedList(); const feedOptions: Parameters<typeof getFeedList>[0] = {
feeds: process.env.FEEDS,
feedFilePath: process.env.FEEDS
? ""
: process.env.FEED_FILE ?? "../config/feeds.json",
};
console.log("feedOptions", JSON.stringify(feedOptions, null, 2));
const feedList = await getFeedList(feedOptions);
const feedListLength = const feedListLength =
Object.entries(feedList).flat(2).length - Object.keys(feedList).length; Object.entries(feedList).flat(2).length - Object.keys(feedList).length;
@ -90,7 +103,7 @@ const finishBuild: () => void = async () => {
data: sortedFeeds, data: sortedFeeds,
errors: errors, errors: errors,
info: buboInfo, info: buboInfo,
yazzyUrl yazzyUrl,
}); });
// write the output to public/index.html // write the output to public/index.html
@ -140,7 +153,7 @@ const processFeed =
item.link = getLink(item); item.link = getLink(item);
const timestamp = new Date(Number.parseInt(item.timestamp)); const timestamp = new Date(Number.parseInt(item.timestamp));
const eightHoursAgo = new Date(); const eightHoursAgo = new Date();
eightHoursAgo.setHours(eightHoursAgo.getHours() - 8); eightHoursAgo.setHours(eightHoursAgo.getHours() - 24);
item.isRecent = timestamp > eightHoursAgo; item.isRecent = timestamp > eightHoursAgo;
} }

View file

@ -23,6 +23,11 @@ env.addFilter("formatTime", (dateString): string => {
return !Number.isNaN(date.getTime()) ? date.toLocaleTimeString() : dateString; return !Number.isNaN(date.getTime()) ? date.toLocaleTimeString() : dateString;
}); });
env.addFilter("formatDateTime", (dateString): string => {
const date: Date = new Date(Number.parseInt(dateString));
return !Number.isNaN(date.getTime()) ? date.toLocaleString() : dateString;
});
env.addGlobal("now", new Date().getTime()); env.addGlobal("now", new Date().getTime());
// load the template // load the template

View file

@ -1,3 +1,4 @@
import { $ } from "bun";
/* /*
There's a little inconsistency with how feeds report certain things like There's a little inconsistency with how feeds report certain things like
title, links and timestamps. These helpers try to normalize that bit and title, links and timestamps. These helpers try to normalize that bit and
@ -75,11 +76,18 @@ export async function parseFeed(response: Response): Promise<JSONValue> {
return (rssFeed && rssFeed) || (jsonFeed && jsonFeed) || {}; return (rssFeed && rssFeed) || (jsonFeed && jsonFeed) || {};
} }
export const getFeedList = async (): Promise<JSONValue> => { export const getFeedList = async ({
feedFilePath,
feeds,
}: { feedFilePath?: string; feeds?: string }): Promise<JSONValue> => {
if (feeds) {
return JSON.parse(feeds);
}
if (!feedFilePath) {
throw new Error("No feed list provided");
}
return JSON.parse( return JSON.parse(
( (await readFile(new URL(feedFilePath, import.meta.url))).toString(),
await readFile(new URL("../config/feeds.json", import.meta.url))
).toString(),
); );
}; };
@ -88,3 +96,18 @@ export const getBuboInfo = async (): Promise<JSONValue> => {
(await readFile(new URL("../package.json", import.meta.url))).toString(), (await readFile(new URL("../package.json", import.meta.url))).toString(),
); );
}; };
export const buildCSS = async (
minify: boolean,
input: string,
destination: string,
): Promise<void> => {
const output =
await $`bun x tailwindcss -i ${input} ${minify ? "--minify" : ""} -o ${destination}`;
if (output.exitCode !== 0) {
const err = new TextDecoder().decode(output.stderr);
throw new Error(`Building tailwind failed: ${err}`);
}
console.log(`Successfully built CSS to ${destination}`);
return;
};

251
tailwind.config.js Normal file
View file

@ -0,0 +1,251 @@
const plugin = require("tailwindcss/plugin");
/** @type {import('tailwindcss').Config} */
export default {
content: ["./config/*.html"],
theme: {
extend: {
fontFamily: {
// from https://github.com/system-fonts/modern-font-stacks
/* System UI fonts are those native to the operating system interface.
* They are highly legible and easy to read at small sizes, contains
* many font weights, and is ideal for UI elements.
*/
system: ["system-ui", "sans-serif"],
/* Transitional typefaces are a mix between Old Style and Modern
* typefaces that was developed during The Enlightenment. One of the
* most famous examples of a Transitional typeface is Times New Roman,
* which was developed for the Times of London newspaper.
*/
transitional: [
"Charter",
"'Bitstream Charter'",
"'Sitka Text'",
"Cambria",
"serif",
],
/* Old Style typefaces are characterized by diagonal stress, low
* contrast between thick and thin strokes, and rounded serifs, and
* were developed in the Renaissance period. One of the most famous
* examples of an Old Style typeface is Garamond.
*/
"old-style": [
"'Iowan Old Style'",
"'Palatino Linotype'",
"'URW Palladio L'",
"P052",
"serif",
],
/* Humanist typefaces are characterized by their organic, calligraphic
* forms and low contrast between thick and thin strokes. These
* typefaces are inspired by the handwriting of the Renaissance period
* and are often considered to be more legible and easier to read than
* other sans-serif typefaces.
*/
humanist: [
"Seravek",
"'Gill Sans Nova'",
"Ubuntu",
"Calibri",
"'DejaVu Sans'",
"source-sans-pro",
"sans-serif",
],
/* Geometric Humanist typefaces are characterized by their clean,
* geometric forms and uniform stroke widths. These typefaces are often
* considered to be modern and sleek in appearance, and are often used
* for headlines and other display purposes. Futura is a famous example
* of this classification.
*/
"gemoetric-humanist": [
"Avenir",
"Montserrat",
"Corbel",
"'URW Gothic'",
"source-sans-pro",
"sans-serif",
],
/* Classical Humanist typefaces are characterized by how the strokes
* subtly widen as they reach the stroke terminals without ending in a
* serif. These typefaces are inspired by classical Roman capitals and
* the stone-carving on Renaissance-period tombstones.
*/
"classical-humanist": [
"Optima",
"Candara",
"'Noto Sans'",
"source-sans-pro",
"sans-serif",
],
/* Neo-Grotesque typefaces are a style of sans-serif that was developed
* in the late 19th and early 20th centuries and is characterized by its
* clean, geometric forms and uniform stroke widths. One of the most
* famous examples of a Neo-Grotesque typeface is Helvetica.
*/
"neo-grotesque": [
"Inter",
"Roboto",
"'Helvetica Neue'",
"'Arial Nova'",
"'Nimbus Sans'",
"Arial",
"sans-serif",
],
/* Monospace Slab Serif typefaces are characterized by their fixed-width
* letters, which have the same width regardless of their shape, and its
* simple, geometric forms. Used to emulate typewriter output for
* reports, tabular work and technical documentation.
*/
"monospace-slab-serif": [
"'Nimbus Mono PS'",
"'Courier New'",
"monospace",
],
/* Monospace Code typefaces are specifically designed for use in
* programming and other technical applications. These typefaces are
* characterized by their monospaced design, which means that all
* letters and characters have the same width, and their clear, legible
* forms.
*/
"monospace-code": [
"ui-monospace",
"'Cascadia Code'",
"'Source Code Pro'",
"Menlo",
"Consolas",
"'DejaVu Sans Mono'",
"monospace",
],
/* Industrial typefaces originated in the late 19th century and was
* heavily influenced by the advancements in technology and industry
* during that time. Industrial typefaces are characterized by their
* bold, sans-serif letterforms, simple and straightforward appearance,
* and the use of straight lines and geometric shapes.
*/
industrial: [
"Bahnschrift",
"'DIN Alternate'",
"'Franklin Gothic Medium'",
"'Nimbus Sans Narrow'",
"sans-serif-condensed",
"sans-serif",
],
/* Rounded typefaces are characterized by the rounded curved letterforms
* and give a softer, friendlier appearance. The rounded edges give the
* typeface a more organic and
* playful feel, making it suitable for use in informal or child-friendly
* designs. The rounded sans-serif style has been popular since the 1950s,
* and it continues to be widely used in advertising, branding, and
* other forms of graphic design.
*/
"rounded-sans": [
"ui-rounded",
"'Hiragino Maru Gothic ProN'",
"Quicksand",
"Comfortaa",
"Manjari",
"'Arial Rounded MT'",
"'Arial Rounded MT Bold'",
"Calibri",
"source-sans-pro",
"sans-serif",
],
/* Slab Serif typefaces are characterized by the presence of thick,
* block-like serifs on the ends of each letterform. These serifs are
* usually unbracketed, meaning they do not have any curved or tapered
* transitions to the main stroke of the letter.
*/
"slab-serif": [
"Rockwell",
"'Rockwell Nova'",
"'Roboto Slab'",
"'DejaVu Serif'",
"'Sitka Small'",
"serif",
],
/* Antique typefaces, also known as Egyptians, are a subset of serif
* typefaces that were popular in the 19th century. They are
* characterized by their block-like serifs and thick uniform stroke
* weight.
*/
antique: [
"Superclarendon",
"'Bookman Old Style'",
"'URW Bookman'",
"'URW Bookman L'",
"'Georgia Pro'",
"Georgia",
"serif",
],
/* Didone typefaces, also known as Modern typefaces, are characterized
* by the high contrast between thick and thin strokes, vertical stress,
* and hairline serifs with no bracketing. The Didone style emerged in
* the late 18th century and gained popularity during the 19th century.
*/
didone: [
"Didot",
"'Bodoni MT'",
"'Noto Serif Display'",
"'URW Palladio L'",
"P052",
"Sylfaen",
"serif",
],
/* Handwritten typefaces are designed to mimic the look and feel of
* handwriting. Despite the vast array of handwriting styles, this font
* stack tend to adopt a more informal and everyday style of handwriting.
*/
handwritten: [
"'Segoe Print'",
"'Bradley Hand'",
"Chilanka",
"TSCu_Comic",
"casual",
"cursive",
],
emoji: [
"'Apple Color Emoji'",
"'Segoe UI Emoji'",
"'Segoe UI Symbol'",
"'Noto Color Emoji'",
],
},
colors: {
/*
* The Arc browser (can) expose its theme color to the pages beneath as
* CSS custom properties.
*/
arc: {
"background-simple": "var(--arc-background-simple-color, #FDF8EBFF)",
maxContrast: "var(--arc-palette-maxContrastColor, #6F540AFF)",
minContrast: "var(--arc-palette-minContrastColor, #FDF8EBFF)",
hover: "var(--arc-palette-hover, #E2DDCAFF)",
foregroundPrimary: "var(--arc-palette-foregroundPrimary, #EBB218FF)",
foregroundSecondary:
"var(--arc-palette-foregroundSecondary, #EBB218FF)",
foregroundTertiary:
"var(--arc-palette-foregroundTertiary, #FDF8EBFF)",
title: "var(--arc-palette-title, #211900FF)",
subtitle: "var(--arc-palette-subtitle, #C5BB96FF)",
background: "var(--arc-palette-background, #F1EEE5FF)",
backgroundExtra: "var(--arc-palette-backgroundExtra, #FEFDFCFF)",
cutout: "var(--arc-palette-cutoutColor, #FDF8EBFF)",
focus: "var(--arc-palette-focus, #B7A97CFF)",
},
},
},
},
plugins: [
plugin(({ addBase, theme }) => {
addBase({
a: {
textDecoration: "underline",
transition: "color 0.2s",
cursor: "pointer",
"&:hover": {
color: theme("colors.arc.subtitle"),
},
},
});
}),
],
};