From f5acd81fdc0bff873e956aa1a9302e5a68b9c95c Mon Sep 17 00:00:00 2001
From: Wesley B <62723358+wesleyboar@users.noreply.github.com>
Date: Mon, 3 Aug 2026 11:48:28 -0500
Subject: [PATCH 1/6] feat(generic): add news/blog component CSS found during
tup-ui development
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Migrated from tup-ui's for-core-styles/components/ (c-news.css,
c-news--read.css, c-news--list.css) — genuine Core-Styles gaps found while
building tup-ui, not tup-specific overrides, so they belong here where
every other project can discover and use them instead of independently
re-patching the same Core-Styles gaps.
c-news.css and c-news--read.css include tup-ui#325's pending edit
(unmerged) composed in, since #325 will stop editing its local copies
once tup-ui deletes them in favor of this. c-feed-list.css is not
migrated: tup-ui#325 and #535 both delete it outright rather than keep it,
so there is nothing to migrate.
---
generic_assets/css/c-news--list.css | 239 ++++++++++++++++++++++++++++
generic_assets/css/c-news--read.css | 171 ++++++++++++++++++++
generic_assets/css/c-news.css | 124 +++++++++++++++
3 files changed, 534 insertions(+)
create mode 100644 generic_assets/css/c-news--list.css
create mode 100644 generic_assets/css/c-news--read.css
create mode 100644 generic_assets/css/c-news.css
diff --git a/generic_assets/css/c-news--list.css b/generic_assets/css/c-news--list.css
new file mode 100644
index 00000000..f352cc6c
--- /dev/null
+++ b/generic_assets/css/c-news--list.css
@@ -0,0 +1,239 @@
+/* TODO: When integrated into Core-Styles, import these */
+/* @tacc/core-styles/src/lib/_imports/tools/x-article-link.css */
+/* @tacc/core-styles/src/lib/_imports/tools/x-truncate.css */
+/* _imports/tools/media-queries.css */
+
+
+
+
+
+/* List */
+
+/* To support rendering list as a grid */
+.c-news--list.as-grid {
+ display: grid;
+ grid-template-columns: repeat( auto-fit, minmax(350px, 1fr) );
+ column-gap: var(--global-space--pattern-pad);
+}
+/* So page title spans all columns */
+.c-news--list.as-grid > .c-news__name {
+ grid-column: 1 / -1;
+}
+
+
+
+
+
+/* Item */
+
+
+
+/* Item (Structure) */
+
+/* For basic layout */
+.c-news--list article {
+ display: grid;
+
+ border-bottom: var(--global-border-width--normal) solid var(--global-color-primary--dark);
+ margin-bottom: var(--article-buffer);
+ padding-bottom: var(--article-buffer);
+}
+.c-news--list .c-news__header { grid-area: head }
+.c-news--list .c-news__visual { grid-area: media }
+.c-news--list .c-news__abstract { grid-area: desc }
+
+/* For conditional layouts */
+.c-news--list:not(.has-media) article {
+ --grid-item-areas:
+ 'head'
+ 'desc';
+
+ --list-item-areas:
+ 'head'
+ 'desc';
+ /* Do not manage what is irrelevant in this layout */
+ --list-item-columns: none;
+}
+.c-news--list.has-media article {
+ --grid-item-areas:
+ 'media'
+ 'head'
+ 'desc';
+
+ --list-item-areas:
+ 'media head'
+ 'media desc';
+ /* To shrinkwrap media and flexible text content */
+ --list-item-columns: minmax(0, max-content) 1fr;
+
+ column-gap: 50px; /* for horz. space between image and content */
+}
+
+/* For layout options */
+.x-news-grid-item {
+ grid-template-areas: var(--grid-item-areas);
+ /* To prevent content from overflowing cell */
+ grid-template-columns: minmax(0, 1fr);
+ /* To prevent vertical stretch of rows */
+ grid-auto-rows: min-content;
+}
+.x-news-list-item {
+ grid-template-areas: var(--list-item-areas);
+ grid-template-columns: var(--list-item-columns);
+ /* To let 'desc' take remaining space (removes gap between head and desc) */
+ grid-template-rows: min-content 1fr;
+}
+@media (width < 768px) /* TODO: When in Core, use @custom-media */ {
+ .c-news--list article {
+ /* TODO: When in Core, use @extend */
+ /* @extend .x-news-grid-item; */
+ grid-template-areas: var(--grid-item-areas);
+ /* To prevent content from overflowing cell */
+ grid-template-columns: minmax(0, 1fr);
+ /* To prevent vertical stretch of rows */
+ grid-auto-rows: min-content;
+ }
+}
+@media (width >= 768px) /* TODO: When in Core, use @custom-media */ {
+ .c-news--list:not(.as-grid) article {
+ /* TODO: When in Core, use @extend */
+ /* @extend .x-news-list-item; */
+ grid-template-areas: var(--list-item-areas);
+ grid-template-columns: var(--list-item-columns);
+ /* To let 'desc' take remaining space (removes gap between head and desc) */
+ grid-template-rows: min-content 1fr;
+ }
+ .c-news--list.as-grid article {
+ /* TODO: When in Core, use @extend */
+ /* @extend .x-news-grid-item; */
+ grid-template-areas: var(--grid-item-areas);
+ /* To prevent content from overflowing cell */
+ grid-template-columns: minmax(0, 1fr);
+ /* To prevent vertical stretch of rows */
+ grid-auto-rows: min-content;
+ }
+}
+
+
+
+
+
+/* Header */
+
+
+
+/* Header (Structure) */
+
+.c-news--list .c-news__header {
+ margin-bottom: 5px;
+}
+
+
+
+/* Header - Title */
+
+.c-news--list .c-news__title {
+ margin-bottom: unset; /* overwrite Core-Styles headings--cms.css */
+}
+.c-news--list .c-news__subtitle {
+ display: none;
+}
+
+/* To style a pill (e.g. "Update" pill in a title) */
+.c-news--list .c-pill:not(:first-child) {
+ margin-left: 0.5ch;
+}
+
+
+
+/* Header - Metadata (Skin) */
+
+.c-news--list .c-news__data li {
+ line-height: unset; /* overwrite html-elements.css */
+}
+
+.c-news--list .c-news__attr {
+ color: var(--global-color-primary--dark);
+}
+.c-news--list .c-news__attr a {
+ color: inherit;
+}
+
+
+
+
+
+/* Visual */
+
+.c-news--list .c-news__media:empty {
+ display: none;
+}
+
+/* To support vertical article layouts */
+/* FAQ: In simple layouts, the media element is the grid cell */
+/* FAQ: In complex layouts, the media element is within the grid cell */
+.x-news-grid-item-media-cell {
+ margin-bottom: 15px; /* to add space between image and content */
+}
+.x-blog-grid-item-media-element-in-cell {
+ max-width: 100%; /* to prevent overflow if column is narrower than image */
+ height: auto; /* to preserve ratio if width is reduced (by max-width: 100%) */
+}
+@media (width < 768px) /* TODO: When in Core, use @custom-media */ {
+ .c-news--list .c-news__media {
+ /* TODO: When in Core, use @extend */
+ /* @extend .x-blog-grid-item-media-cell; */
+ margin-bottom: 15px; /* to add space between image and content */
+ & img {
+ /* TODO: When in Core, use @extend */
+ /* @extend .x-blog-grid-item-media-element-in-cell; */
+ max-width: 100%; /* to prevent overflow if column is narrower than image */
+ height: auto; /* to preserve ratio if width is reduced (by max-width: 100%) */
+ }
+ }
+}
+@media (width >= 768px) /* TODO: When in Core, use @custom-media */ {
+ .c-news--list.as-grid .c-news__media {
+ /* TODO: When in Core, use @extend */
+ /* @extend .x-blog-grid-item-media-cell; */
+ margin-bottom: 15px; /* to add space between image and content */
+ & img {
+ /* TODO: When in Core, use @extend */
+ /* @extend .x-blog-grid-item-media-element-in-cell; */
+ max-width: 100%; /* to prevent overflow if column is narrower than image */
+ height: auto; /* to preserve ratio if width is reduced (by max-width: 100%) */
+ }
+ }
+}
+
+
+
+
+
+/* Content */
+
+.c-news--list .c-news__abstract {
+ /* TODO: When in Core, use @extend */
+ /* @extend %x-truncate--many-lines; */
+ --lines: 2;
+
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+
+ overflow: hidden;
+ -webkit-line-clamp: var(--lines);
+
+ --lines: 4;
+
+ line-height: 1.5;
+ color: var(--global-color-primary--dark);
+}
+.c-news--list .c-news__abstract p:last-child {
+ margin-bottom: 0 /* overwrite core-styles.cms */
+}
+
+/* To undo inline content styles */
+/* FAQ: In case author pasted such markup from another source */
+.c-news--list .c-news__abstract [style] {
+ all: revert !important; /* force undo all inline styles */
+}
diff --git a/generic_assets/css/c-news--read.css b/generic_assets/css/c-news--read.css
new file mode 100644
index 00000000..a840366c
--- /dev/null
+++ b/generic_assets/css/c-news--read.css
@@ -0,0 +1,171 @@
+/* TODO: When integrated into Core-Styles, import these */
+/* @tacc/core-styles/src/lib/_imports/objects/o-offset-content.css */
+/* @tacc/core-styles/src/lib/_imports/tools/x-figure.css */
+/* @tacc/core-styles/src/lib/_imports/tools/x-blockquote.css */
+
+
+
+
+
+/* Root */
+
+.c-news--read article {
+ --header-buffer: calc( var(--global-space--grid-gap) / 2 );
+
+ max-width: 775px;
+ margin-inline: auto;
+}
+
+
+
+
+
+/* Header (Structure) */
+
+.c-news--read .c-news__header {
+ grid-template-areas:
+ 'head head'
+ 'subh subh'
+ 'cats link'
+ 'tags tags'
+ 'attr attr';
+}
+.c-news--read .c-news__title,
+.c-news--read .c-news__subtitle {
+ margin-bottom: var(--header-buffer);
+}
+.c-news--read .c-news__title {
+ font-size: var(--global-font-size--xxx-large);
+
+ border-bottom: var(--global-border-width--normal) solid var(--global-color-primary--dark);
+}
+.c-news--read .c-news__subtitle {
+ font-weight: normal;
+ font-size: var(--global-font-size--large);
+}
+
+
+
+
+
+/* Media & Content */
+
+.c-news--read .c-news__media,
+.c-news--read .c-news__content {
+ --news-read-media-buffer: 45px;
+
+ margin-block: var(--news-read-media-buffer) 60px;
+}
+
+/* To undo inline content styles */
+/* FAQ: In case author pasted such markup from another source */
+.c-news--read .c-news__content [style]:not(
+ [data-style="admin"], /* HACK: So CMS admin can override this */
+) {
+ all: revert !important; /* force undo all inline styles */
+}
+
+
+
+/* Media & Content - Media */
+
+/* To mimic Bootstrap `.img-fluid` */
+.c-news--read img.c-news__media /* WARNING: Untested */,
+.c-news--read .c-news__media img {
+ max-width: 100%;
+ height: auto;
+}
+/* To support vertical layouts at narrow viewports */
+@media (width < 768px) /* TODO: When in Core, use @custom-media */ {
+ .c-news--read .c-news__media {
+ display: grid;
+ justify-content: center;
+ margin-bottom: var(--news-read-media-buffer);
+ }
+}
+/* To support horizontal layouts at wide viewports */
+@media (width >= 768px) /* TODO: When in Core, use @custom-media */ {
+ .c-news--read .c-news__media {
+ float: left;
+ margin-right: var(--news-read-media-buffer);
+ }
+}
+
+/* To prevent footer on right side of page */
+/* FAQ: Because of `.c-news--read .c-news__media`'s `float: left` */
+.c-news--read .c-news__media + .c-news__content::after {
+ /* from Bootstrap `clearfix` */
+ display: block;
+ content: "";
+ clear: both;
+}
+
+
+
+/* Media & Content - Content */
+
+/* FAQ: Read page CAN have abstract */
+/* https://github.com/TACC/Core-CMS/pull/594 */
+.c-news--read .c-news__abstract,
+.c-news--read .c-news__content {
+ font-size: var(--global-font-size--medium);
+ line-height: 2;
+}
+/* Add space between all list items */
+/* FAQ: Use case is list items with as much text as a paragraph */
+.c-news--read .c-news__abstract li + li,
+.c-news--read .c-news__content li + li {
+ margin-top: 0.5em;
+}
+
+/* To reduce space between "Original Message" and its content */
+.c-update__header + .c-news__content {
+ margin-top: unset; /* ovewrite c-news--read.css */
+}
+
+
+
+/* Media & Content - Alignment */
+/* FAQ: The .align-... classes come from Bootstrap Picture */
+/* FAQ: The .blockquote.text-... classes come from Bootstrap Blockquote */
+
+.c-news--read .c-news__content .align-left {
+ /* TODO: When in Core, use @extend */
+ /* @extend .o-offset-content--left; */
+ /* NOTE: Ignore in TUP-CMS, cuz c-news only for User Updates (no images) */
+}
+.c-news--read .c-news__content .align-right {
+ /* TODO: When in Core, use @extend */
+ /* @extend .o-offset-content--right; */
+ /* NOTE: Ignore in TUP-CMS, cuz c-news only for User Updates (no images) */
+}
+
+/* To remove margin on narrow screens */
+/* To overwrite @tacc/core-styles/…/components/align.css */
+@media (width < 768px) /* TODO: When in Core, use @custom-media */ {
+ .c-news--read .c-news__content .align-center,
+ .c-news--read .c-news__content .align-right,
+ .c-news--read .c-news__content .align-left {
+ max-width: unset;
+ }
+ .c-news--read .c-news__content .align-right,
+ .c-news--read .c-news__content .align-left {
+ float: unset;
+ margin-bottom: unset;
+ }
+ .c-news--read .c-news__content .align-right {
+ margin-left: unset;
+ }
+ .c-news--read .c-news__content .align-left {
+ margin-right: unset;
+ }
+}
+
+/* To reduce image width on medium screens */
+@media (width < 768px) and (width < 992px) /* TODO: When in Core, use @custom-media */ {
+ .c-news--read .c-news__content .align-center,
+ .c-news--read .c-news__content .align-right,
+ .c-news--read .c-news__content .align-left {
+ max-width: 50%;
+ }
+}
diff --git a/generic_assets/css/c-news.css b/generic_assets/css/c-news.css
new file mode 100644
index 00000000..33535d75
--- /dev/null
+++ b/generic_assets/css/c-news.css
@@ -0,0 +1,124 @@
+/* TODO: When integrated into Core-Styles, import these */
+/* @tacc/core-styles/src/lib/_imports/components/c-tag.css */
+
+@import url("./c-news--read.css");
+@import url("./c-news--list.css");
+
+
+
+
+
+/* Variables */
+
+.c-news {
+ --article-buffer: 20px;
+}
+
+
+
+/* Generic */
+
+.c-news {
+ /* To control absolute position of descendants e.g. `.blog-visual` */
+ position: relative;
+}
+
+/* TODO: Share styles between c-news and c-feed-list (`time:not(…)`) */
+.c-news article time:not(:is(h1, h2, h3, h4, h5, h6) *) {
+ color: var(--global-color-secondary--normal);
+ font-weight: var(--medium);
+ text-transform: uppercase;
+}
+
+
+
+
+
+/* Header */
+
+.c-news__header {
+ display: grid;
+ grid-template-areas:
+ 'cats'
+ 'tags'
+ 'attr'
+ 'head'
+ 'subh';
+}
+.c-news__title { grid-area: head }
+.c-news__subtitle { grid-area: subh }
+.c-news__attr { grid-area: attr }
+.c-news__cats { grid-area: cats }
+.c-news__tags { grid-area: tags }
+
+.c-news__data {
+ list-style: none;
+
+ padding-left: 0; /* overwrite html-elements.css */
+ margin-bottom: 0.25em; /* overwrite html-elements.css */
+
+ font-size: var(--global-font-size--medium);
+}
+
+
+
+/* Metadata */
+
+/* To layout data */
+.c-news__attr,
+.c-news__tags,
+.c-news__cats {
+ display: flex;
+ flex-direction: row;
+ gap: 1em;
+}
+.c-news__attr {
+ justify-content: space-between;
+}
+.c-news__date {
+ order: -1
+}
+
+/* To conditionally hide tags & categories */
+.c-news.no-tags .c-news__tags,
+.c-news.no-categories .c-news__cats {
+ display: none;
+}
+
+/* To hide empty tags & categories */
+.c-news__tags:empty,
+.c-news__cats:empty {
+ display: none;
+}
+
+/* To style categories as "tags" (the UI pattern) */
+.c-news__cats a {
+ /* TODO: When integrated into Core-Styles, uncomment this */
+ /* @extend :--c-tag; */
+
+ display: inline-block;
+
+ color: var(--global-color-primary--xx-light);
+ background-color: var(--global-color-primary--xx-dark);
+
+ font-size: var(--global-font-size--x-small);
+}
+
+/* To style tags as "pills" (the UI pattern) */
+.c-news__tags a {
+ /* TODO: When available in Core-Styles, uncomment this */
+ /* @extend :--c-pill; */
+
+ background-color: var(--global-color-primary--light);
+}
+
+/* So byline text is all on one line */
+.c-news__data address {
+ display: inline;
+}
+
+/* To style a pill (e.g. "Update" pill in a title) */
+.c-news .c-pill {
+ vertical-align: middle;
+ transform: translateY(-0.125em);
+}
From e7d15fd6c2c9f907063252e17f415103233dfeea Mon Sep 17 00:00:00 2001
From: Wesley B <62723358+wesleyboar@users.noreply.github.com>
Date: Mon, 3 Aug 2026 14:35:26 -0500
Subject: [PATCH 2/6] fix(generic): restore dropped blank line in
c-news--list.css
Off-by-one blank line from the initial copy; content now matches
tup-ui's source file exactly.
---
generic_assets/css/c-news--list.css | 1 +
1 file changed, 1 insertion(+)
diff --git a/generic_assets/css/c-news--list.css b/generic_assets/css/c-news--list.css
index f352cc6c..2540157e 100644
--- a/generic_assets/css/c-news--list.css
+++ b/generic_assets/css/c-news--list.css
@@ -118,6 +118,7 @@
+
/* Header */
From 001fe3262d224802e26cd838d2514e682eecb1a1 Mon Sep 17 00:00:00 2001
From: Wesley B <62723358+wesleyboar@users.noreply.github.com>
Date: Mon, 3 Aug 2026 15:37:43 -0500
Subject: [PATCH 3/6] feat(generic): add core-styles-feats.css, load it via the
ad-hoc CSS snippet
c-news.css needs layer(base) to preserve its original cascade position,
but a plain can't assign a layer. Rather than add another raw