mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-24 07:12:18 +10:00
feat(stylesheet): expose the item header row to Semantic CSS (#3345)
Section item headers render the title and its trailing date inside a shared
split row styled with `flex-wrap: wrap`. When the title is long the date wraps
onto its own line and left-aligns instead of staying pinned right, which reads
as inconsistent down a list of certifications.
That row had no selector. It is a bare View, so it never reached the semantic
tree: `item-header` matches the box around the row, and the title and date are
text nodes that layout properties do not apply to. There was no stylesheet that
could reach it.
Expose it as `template-part[name="item-header-row"]`, shared by every template
because the row comes from the shared section components. Awards,
certifications, projects and publications are covered; experience, education
and volunteer stack two rows and hand their headers to the
`inline-item-header-*` parts on some templates, so they are left alone.
Readers can now write:
@version 1;
template-part[name="item-header-row"] { flex-wrap: nowrap; }
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
export const azurillSemanticManifest = {
|
||||
template: "azurill",
|
||||
@@ -10,6 +11,7 @@ export const azurillSemanticManifest = {
|
||||
header: { region: "header", placement: "main" },
|
||||
specialSummary: null,
|
||||
parts: [
|
||||
itemHeaderRowPart,
|
||||
{
|
||||
name: "timeline-line",
|
||||
key: "timeline-line",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
export const bronzorSemanticManifest = {
|
||||
template: "bronzor",
|
||||
@@ -9,6 +10,7 @@ export const bronzorSemanticManifest = {
|
||||
header: { region: "header", placement: "main" },
|
||||
specialSummary: null,
|
||||
parts: [
|
||||
itemHeaderRowPart,
|
||||
{
|
||||
name: "interleaved-section-row",
|
||||
key: "interleaved-section-row",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
export const chikoritaSemanticManifest = {
|
||||
template: "chikorita",
|
||||
@@ -10,6 +11,7 @@ export const chikoritaSemanticManifest = {
|
||||
header: { region: "header", placement: "main" },
|
||||
specialSummary: null,
|
||||
parts: [
|
||||
itemHeaderRowPart,
|
||||
{
|
||||
name: "contact-row-primary",
|
||||
key: "contact-row-primary",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
const borderedItemHeaderSectionTypes = [
|
||||
"profiles",
|
||||
@@ -26,6 +27,7 @@ export const ditgarSemanticManifest = {
|
||||
header: { region: "header", placement: "sidebar" },
|
||||
specialSummary: { region: "featured", placement: "main", source: "main-with-header" },
|
||||
parts: [
|
||||
itemHeaderRowPart,
|
||||
{
|
||||
name: "featured-summary",
|
||||
key: "featured-summary",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
export const dittoSemanticManifest = {
|
||||
template: "ditto",
|
||||
@@ -10,6 +11,7 @@ export const dittoSemanticManifest = {
|
||||
header: { region: "header", placement: "main" },
|
||||
specialSummary: null,
|
||||
parts: [
|
||||
itemHeaderRowPart,
|
||||
{
|
||||
name: "header-band",
|
||||
key: "header-band",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
export const gengarSemanticManifest = {
|
||||
template: "gengar",
|
||||
@@ -11,6 +12,7 @@ export const gengarSemanticManifest = {
|
||||
header: { region: "header", placement: "sidebar" },
|
||||
specialSummary: { region: "featured", placement: "main", source: "main-with-header" },
|
||||
parts: [
|
||||
itemHeaderRowPart,
|
||||
{
|
||||
name: "featured-summary",
|
||||
key: "featured-summary",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
export const glalieSemanticManifest = {
|
||||
template: "glalie",
|
||||
@@ -10,6 +11,7 @@ export const glalieSemanticManifest = {
|
||||
header: { region: "header", placement: "sidebar" },
|
||||
specialSummary: null,
|
||||
parts: [
|
||||
itemHeaderRowPart,
|
||||
{
|
||||
name: "sidebar-background",
|
||||
key: "sidebar-background",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
export const kakunaSemanticManifest = {
|
||||
template: "kakuna",
|
||||
@@ -9,5 +10,5 @@ export const kakunaSemanticManifest = {
|
||||
],
|
||||
header: { region: "header", placement: "main" },
|
||||
specialSummary: null,
|
||||
parts: [],
|
||||
parts: [itemHeaderRowPart],
|
||||
} as const satisfies TemplateSemanticManifest;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
export const laprasSemanticManifest = {
|
||||
template: "lapras",
|
||||
@@ -9,5 +10,5 @@ export const laprasSemanticManifest = {
|
||||
],
|
||||
header: { region: "header", placement: "main" },
|
||||
specialSummary: null,
|
||||
parts: [],
|
||||
parts: [itemHeaderRowPart],
|
||||
} as const satisfies TemplateSemanticManifest;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
export const leafishSemanticManifest = {
|
||||
template: "leafish",
|
||||
@@ -10,6 +11,7 @@ export const leafishSemanticManifest = {
|
||||
header: { region: "header", placement: "main" },
|
||||
specialSummary: { region: "header", placement: "main", source: "always" },
|
||||
parts: [
|
||||
itemHeaderRowPart,
|
||||
{
|
||||
name: "header-intro",
|
||||
key: "header-intro",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
const inlineHeaderSectionTypes = ["experience", "education", "volunteer"] as const;
|
||||
|
||||
@@ -12,6 +13,7 @@ export const meowthSemanticManifest = {
|
||||
header: { region: "header", placement: "main" },
|
||||
specialSummary: null,
|
||||
parts: [
|
||||
itemHeaderRowPart,
|
||||
{
|
||||
name: "inline-item-header-leading",
|
||||
key: "inline-item-header-leading",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
export const onyxSemanticManifest = {
|
||||
template: "onyx",
|
||||
@@ -9,5 +10,5 @@ export const onyxSemanticManifest = {
|
||||
],
|
||||
header: { region: "header", placement: "main" },
|
||||
specialSummary: null,
|
||||
parts: [],
|
||||
parts: [itemHeaderRowPart],
|
||||
} as const satisfies TemplateSemanticManifest;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
export const pikachuSemanticManifest = {
|
||||
template: "pikachu",
|
||||
@@ -10,6 +11,7 @@ export const pikachuSemanticManifest = {
|
||||
header: { region: "header", placement: "main" },
|
||||
specialSummary: null,
|
||||
parts: [
|
||||
itemHeaderRowPart,
|
||||
{
|
||||
name: "header-divider",
|
||||
key: "header-divider",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
export const rhyhornSemanticManifest = {
|
||||
template: "rhyhorn",
|
||||
@@ -10,6 +11,7 @@ export const rhyhornSemanticManifest = {
|
||||
header: { region: "header", placement: "main" },
|
||||
specialSummary: null,
|
||||
parts: [
|
||||
itemHeaderRowPart,
|
||||
{
|
||||
name: "contact-item-content",
|
||||
key: "contact-item-content",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateSemanticManifest } from "../../semantic/template-manifest";
|
||||
import { itemHeaderRowPart } from "../../semantic/shared-parts";
|
||||
|
||||
export const scizorSemanticManifest = {
|
||||
template: "scizor",
|
||||
@@ -9,6 +10,7 @@ export const scizorSemanticManifest = {
|
||||
header: { region: "header", placement: "main" },
|
||||
specialSummary: null,
|
||||
parts: [
|
||||
itemHeaderRowPart,
|
||||
{
|
||||
name: "header-name-rule",
|
||||
key: "header-name-rule",
|
||||
|
||||
@@ -42,6 +42,7 @@ import {
|
||||
useSemanticSectionNodeKey,
|
||||
} from "../../semantic/context";
|
||||
import { semanticNodeKeys } from "../../semantic/node-keys";
|
||||
import { ITEM_HEADER_ROW_PART_KEYS } from "../../semantic/shared-parts";
|
||||
import { getSectionItemRows, getSectionItemsLayout, shouldUseSectionTimeline } from "./columns";
|
||||
import { getWebsiteDisplayText } from "./contact";
|
||||
import {
|
||||
@@ -612,6 +613,25 @@ const useSectionSplitRowStyle = () => {
|
||||
);
|
||||
};
|
||||
|
||||
type ItemHeaderRowProps = {
|
||||
children: ReactNode;
|
||||
style: StyleInput;
|
||||
};
|
||||
|
||||
/**
|
||||
* The title/date row inside a section item header, exposed to Semantic CSS as
|
||||
* `template-part[name="item-header-row"]`.
|
||||
*
|
||||
* It has to be addressable on its own: the row carries `flex-wrap: wrap`, so a long title pushes
|
||||
* the trailing date onto its own line, and `item-header` selects the box around the row rather than
|
||||
* the row itself. The owning item-header key comes from the surrounding provider.
|
||||
*/
|
||||
const ItemHeaderRow = ({ children, style }: ItemHeaderRowProps) => (
|
||||
<SemanticTemplatePartView partKeys={ITEM_HEADER_ROW_PART_KEYS} style={composeStyles(style)}>
|
||||
{children}
|
||||
</SemanticTemplatePartView>
|
||||
);
|
||||
|
||||
const SectionItemHeader = ({ children }: SectionItemHeaderProps) => {
|
||||
const itemNodeKey = useSemanticNodeKey();
|
||||
const itemHeaderNodeKey = itemNodeKey ? semanticNodeKeys.itemHeader(itemNodeKey) : undefined;
|
||||
@@ -1109,14 +1129,14 @@ const ProjectsSection = ({ sectionId = "projects", sectionData }: ItemSectionPro
|
||||
{items.map((item) => (
|
||||
<SectionItem key={item.id} itemId={item.id}>
|
||||
<SectionItemHeader>
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<ItemHeaderRow style={composeStyles(splitRowStyle)}>
|
||||
<ItemTitle field="name" website={item.website}>
|
||||
{item.name}
|
||||
</ItemTitle>
|
||||
<Text semanticField="period" style={composeStyles(alignEndStyle)}>
|
||||
{item.period}
|
||||
</Text>
|
||||
</View>
|
||||
</ItemHeaderRow>
|
||||
</SectionItemHeader>
|
||||
|
||||
<RichText semanticField="description">{item.description}</RichText>
|
||||
@@ -1232,14 +1252,14 @@ const AwardsSection = ({ sectionId = "awards", sectionData }: ItemSectionProps<A
|
||||
{items.map((item) => (
|
||||
<SectionItem key={item.id} itemId={item.id}>
|
||||
<SectionItemHeader>
|
||||
<View style={composeStyles(splitRowStyle, awardTitleDateRowStyle)}>
|
||||
<ItemHeaderRow style={composeStyles(splitRowStyle, awardTitleDateRowStyle)}>
|
||||
<ItemTitle field="title" website={item.website} bold={false}>
|
||||
{item.title}
|
||||
</ItemTitle>
|
||||
<Text semanticField="date" style={composeStyles(alignEndStyle)}>
|
||||
{item.date}
|
||||
</Text>
|
||||
</View>
|
||||
</ItemHeaderRow>
|
||||
<Text semanticField="awarder">{item.awarder}</Text>
|
||||
</SectionItemHeader>
|
||||
<RichText semanticField="description">{item.description}</RichText>
|
||||
@@ -1270,14 +1290,14 @@ const CertificationsSection = ({
|
||||
{items.map((item) => (
|
||||
<SectionItem key={item.id} itemId={item.id}>
|
||||
<SectionItemHeader>
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<ItemHeaderRow style={composeStyles(splitRowStyle)}>
|
||||
<ItemTitle field="title" website={item.website}>
|
||||
{item.title}
|
||||
</ItemTitle>
|
||||
<Text semanticField="date" style={composeStyles(alignEndStyle)}>
|
||||
{item.date}
|
||||
</Text>
|
||||
</View>
|
||||
</ItemHeaderRow>
|
||||
<Text semanticField="issuer">{item.issuer}</Text>
|
||||
</SectionItemHeader>
|
||||
|
||||
@@ -1306,14 +1326,14 @@ const PublicationsSection = ({ sectionId = "publications", sectionData }: ItemSe
|
||||
{items.map((item) => (
|
||||
<SectionItem key={item.id} itemId={item.id}>
|
||||
<SectionItemHeader>
|
||||
<View style={composeStyles(splitRowStyle)}>
|
||||
<ItemHeaderRow style={composeStyles(splitRowStyle)}>
|
||||
<ItemTitle field="title" website={item.website}>
|
||||
{item.title}
|
||||
</ItemTitle>
|
||||
<Text semanticField="date" style={composeStyles(alignEndStyle)}>
|
||||
{item.date}
|
||||
</Text>
|
||||
</View>
|
||||
</ItemHeaderRow>
|
||||
|
||||
<Text semanticField="publisher">{item.publisher}</Text>
|
||||
</SectionItemHeader>
|
||||
|
||||
Reference in New Issue
Block a user