Skip to content

Commit 86468b7

Browse files
authored
Merge pull request #45937 from github/repo-sync
Repo sync
2 parents ba92304 + 7e6e992 commit 86468b7

8 files changed

Lines changed: 151 additions & 6 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
Cost centers are available with {% data variables.product.prodname_enterprise %}
2-
<a href="https://github.com/account/enterprises/new?ref_product=ghec&ref_type=trial&ref_style=button&ref_plan=enterprise" target="_blank" class="btn btn-primary mt-3 mr-3 no-underline"><span>Set up a trial of {% data variables.product.prodname_ghe_cloud %}</span> {% octicon "link-external" height:16 aria-label="link-external" %}</a>
2+
<br><a href="https://github.com/account/enterprises/new?ref_product=ghec&ref_type=trial&ref_style=button&ref_plan=enterprise" target="_blank" class="btn btn-primary mt-3 mr-3 no-underline"><span>Set up a trial of {% data variables.product.prodname_ghe_cloud %}</span> {% octicon "link-external" height:16 aria-label="link-external" %}</a>

data/variables/secret-scanning.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ pricing-calculator: 'pricing calculator'
2020
# Secret risk assessment call to action links. If changing the links below, also update the hard-coded link in /code-security/index.md
2121
secret-risk-assessment-cta-link: 'https://github.com/get_started?with=risk-assessment'
2222
secret-risk-assessment-cta-text: 'Run a security risk assessment'
23-
secret-risk-assessment-cta-product: '[<span class="btn btn-primary mt-3 mr-3 no-underline">{% data variables.secret-scanning.secret-risk-assessment-cta-text %}</span>](https://github.com/get_started?with=risk-assessment)'
23+
# Keep this CTA as a raw <a>, matching every other button in the content. The button
24+
# styles are all qualified `a.btn`, so the `[<span class="btn">LABEL](URL)` form puts
25+
# the classes on an inner span and the button silently misses them.
26+
secret-risk-assessment-cta-product: '<a href="https://github.com/get_started?with=risk-assessment" class="btn btn-primary mt-3 mr-3 no-underline"><span>{% data variables.secret-scanning.secret-risk-assessment-cta-text %}</span></a>'
2427

2528
# Combined to provide a secret to demonstrate push protection. Dummy secret, no access.
2629
learner-example-secret-a: 'secret_scanning_ab85fc6f8d76'

src/content-render/stylesheets/markdown-overrides.scss

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,81 @@
5555
margin-inline-start: 0.5rem; // Additional spacing to prevent bullet collision (direct children only)
5656
}
5757
}
58+
59+
// A CTA button written on its own line in markdown — `<a class="btn btn-primary
60+
// mt-3 …">` — becomes its own <p>, and that paragraph already carries the 16px
61+
// rhythm margin. The `mt-3` utility then stacks a second 16px inside it, so the
62+
// button ends up 32px below the preceding line but only 16px above the next one.
63+
// Drop the utility when the button is alone in its paragraph and let the
64+
// paragraph margin do the spacing, which puts the CTA on the same rhythm as
65+
// every other block. `!important` is required because Primer's spacing
66+
// utilities are themselves !important.
67+
//
68+
// `:only-child` is doing real work here — it is what keeps the two cases apart:
69+
// - CTA callouts (`product:`/`permissions:` frontmatter) put the button after
70+
// a <br> INSIDE the prose paragraph, so there is no paragraph margin above
71+
// it and `mt-3` is the only thing separating it from the text.
72+
// - The side-by-side Yes/No `.btn-outline` pairs are two buttons in one
73+
// paragraph.
74+
// Neither is an only child, so both keep their margin.
75+
.markdown-body p > a.btn:only-child {
76+
margin-top: 0 !important;
77+
}
78+
79+
// @primer/css holds `.btn` at `white-space: nowrap`, which a button cannot
80+
// honour and still stay inside a narrow column. The longest CTA label — "Set up
81+
// a trial of GitHub Enterprise Cloud", 322px — is wider than the article column
82+
// below a ~420px viewport and wider than the callout's text column below ~390px,
83+
// so the button ran past the content edge and was clipped.
84+
//
85+
// Letting the label wrap fixes it with no breakpoint to guess at. An
86+
// inline-block is shrink-to-fit — min(max-content, available) — so
87+
// `white-space: normal` changes nothing until max-content exceeds the space
88+
// available: at every width where the button already fits it still renders on
89+
// one line, byte-identical. That also makes it self-correcting for longer
90+
// translated labels and for the narrower column a callout gives the same button.
91+
.markdown-body a.btn,
92+
.permissions-statement a.btn,
93+
.product-statement a.btn {
94+
white-space: normal;
95+
96+
// Wrapping alone orphaned the trailing octicon on a line of its own: the
97+
// space between the label <span> and the icon is a valid break point, and the
98+
// label filled the first line exactly. Laying the button out as a flex row
99+
// instead lets the label wrap within itself and keeps the icon beside it,
100+
// vertically centred. At widths where nothing wraps the result is within a
101+
// pixel of the inline-block it replaces: same 17px left inset, same 21px
102+
// right inset, same 32px height, still one line. The `gap` below covers the
103+
// one thing that does change.
104+
display: inline-flex;
105+
align-items: center;
106+
107+
// Flex layout eats the one thing that was separating the label from the icon.
108+
// The markup is `<span>Label</span> {% octicon "link-external" %}`, and that
109+
// literal space does survive Liquid and the markdown pipeline as a real text
110+
// node — but a whitespace-only text node between two flex items is not itself
111+
// a flex item, so no box is generated for it and the label ends up touching
112+
// the icon. `gap` puts the space back.
113+
//
114+
// 4px rather than the measured width of that space glyph, because a space is
115+
// font- and locale-dependent — it measures differently on two machines here —
116+
// while 4px is the value Primer itself already uses between a button's icon
117+
// and its label. The button ends up a fraction of a pixel wider than it was
118+
// rather than most of a space narrower, on a number the design system owns.
119+
//
120+
// Only the label/icon gap is restored. Primer's `.btn .octicon` also carries
121+
// `margin-right: 4px`, which assumes a LEADING icon and so lands outside the
122+
// trailing icon on these CTAs, giving them 21px of inset on the right against
123+
// 17px on the left. That asymmetry is what ships today, so it stays — zeroing
124+
// it would restyle every CTA on the site, which is a different change from
125+
// keeping a long label inside its column.
126+
gap: 4px;
127+
128+
// The octicon is a flex item now, and flex items shrink before their container
129+
// overflows. Once the label wraps, the icon is the only thing left to give, so
130+
// the 16px glyph was rendering at 11px in a 240px callout column. It is a
131+
// fixed-size icon; the label is what should absorb a narrow column.
132+
.octicon {
133+
flex-shrink: 0;
134+
}
135+
}

src/fixtures/fixtures/content/get-started/foo/page-with-permissions-and-product-callout.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,15 @@ versions:
1515
Note that this page uses the `product` and `permissions` frontmatter property. So it should
1616
result in a call out box rendered with two messages. But only if the version is *not*
1717
Enterprise Server.
18+
19+
<!--
20+
The only CTA button in the fixture content: the regression guard for the `:not(.btn)`
21+
exclusion in src/frame/stylesheets/article-link-overrides.scss, scanned by axe via
22+
src/fixtures/tests/playwright-a11y.spec.ts. It has to be `btn-primary` (only the filled
23+
variant puts the label on a coloured fill, where the override's link blue fell under
24+
4.5:1) and it has to be in the BODY, not in `product:` — the frontmatter callouts render
25+
outside `.markdown-body`, and a CTA there would also break the byte-for-byte assertions
26+
in src/fixtures/tests/permissions-callout.ts.
27+
-->
28+
29+
<a href="https://github.com/pricing" target="_blank" class="btn btn-primary mt-3 mr-3 no-underline"><span>Sign up for {% data variables.product.prodname_pages %}</span> {% octicon "link-external" %}</a>

src/fixtures/tests/playwright-a11y.spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ const SEARCH_TESTS = !!process.env.ELASTICSEARCH_URL
77
const pages: { [key: string]: string } = {
88
category: '/actions/category',
99
codeAnnotations: '/get-started/markdown/code-annotations',
10+
// The only fixture page that renders a CTA button. A `.btn-primary` anchor is the
11+
// one shape the brand article-link override can drive under 4.5:1 — its label sits
12+
// on a coloured fill rather than the page background — which is exactly what it did
13+
// before `:not(.btn)` was added to
14+
// src/frame/stylesheets/article-link-overrides.scss. Without this entry that
15+
// exclusion has no test at all.
16+
ctaButton: '/get-started/foo/page-with-permissions-and-product-callout',
1017
homepage: '/',
1118
learningPath:
1219
'/code-security/getting-started/quickstart?learn=foo_bar&learnProduct=code-security',

src/frame/components/article/ArticleInlineLayout.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ export const ArticleInlineLayout = ({
3232
)}
3333

3434
{introCallOuts && (
35-
<div style={{ gridArea: 'intro' }} className="f4 mb-4">
35+
// `mt-4` (24px) matches the gap the grid layout gets from
36+
// .belowIntroPlacement's own bottom margin. It is needed here because
37+
// this layout puts the callouts in a separate wrapper from the intro,
38+
// so the copy-markdown control is the last child of ITS wrapper and
39+
// that rule cannot reach across. Without it the control sat flush on
40+
// the callout box's top border.
41+
<div style={{ gridArea: 'intro' }} className="f4 mt-4 mb-4">
3642
{introCallOuts}
3743
</div>
3844
)}

src/frame/components/article/ViewMarkdownButton.module.scss

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,37 @@
108108
// The control's placement below the article lede. The margin sets the gap from
109109
// the lede — the Lead's own `mb-3` collapses into it, so this value wins — while
110110
// the header's bottom padding provides the space down to the rule beneath.
111+
//
112+
// Both gaps are spelled as Primer's step-4 spacer rather than a bare `1.5rem`.
113+
// The bottom one has to be: the inline layout sets the same gap from TSX with
114+
// `mt-4`, which compiles to exactly this `var(--base-size-24, 24px)`, and
115+
// `1.5rem` and `mt-4` grep as nothing in common. The top one follows so that
116+
// "match the gap above" below stays literally true. This is the one token here
117+
// that is not `--brand-*`, and it still resolves: brand's main.css defines the
118+
// whole `--base-size-*` scale at `:root` (@primer/primitives' size.css, its
119+
// other home, is one of the files this app never imports).
111120
.belowIntroPlacement {
112-
margin-top: 1.5rem;
121+
margin-top: var(--base-size-24, 24px);
122+
123+
// ...but the header's bottom padding only reaches the control when the
124+
// control is the last thing in the header. On pages that also render intro
125+
// callouts — the "Who can use this feature?" box, or the platform/tool
126+
// pickers — those are siblings that follow it, and the control sat flush
127+
// against the box's top border with no gap at all. Match the gap above, so
128+
// the control is evenly spaced between the lede and whatever follows.
129+
//
130+
// `:not(:last-child)` keeps this off the pages where nothing follows, which
131+
// already get their spacing from the header padding and would otherwise gain
132+
// a second 24px.
133+
//
134+
// This rule only ever fires in the GRID layout, where ArticlePage hands the
135+
// control and the callouts to `intro` as siblings. The inline layout puts
136+
// them in two separate wrappers, so the control is the last child of its own
137+
// and this selector cannot reach across — ArticleInlineLayout.tsx sets the
138+
// identical gap by hand with `mt-4` there instead. The two are one visual gap
139+
// and have to stay equal; nothing enforces that but this note and the shared
140+
// token spelling, so change both or neither.
141+
&:not(:last-child) {
142+
margin-bottom: var(--base-size-24, 24px);
143+
}
113144
}

src/frame/stylesheets/article-link-overrides.scss

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,21 @@
2323
// semantic pair keeps this independent of any ancestor that re-maps the
2424
// component token — breadcrumbs-overrides.scss does exactly that.
2525
//
26-
// Two exclusions, both because this selector outweighs the rules that
26+
// Three exclusions, all because this selector outweighs the rules that
2727
// currently keep those anchors uncoloured:
2828
// - `[href]` — @primer/css holds `.markdown-body a:not([href])` at
2929
// `color: inherit`, for the bare named anchors markdown emits.
3030
// - `:not(.heading-link)` — heading anchors wrap the entire heading text,
3131
// and headings.scss holds them at `color: unset`.
32-
a[href]:not(.heading-link) {
32+
// - `:not(.btn)` — CTA buttons in content are plain anchors carrying
33+
// @primer/css's button classes (`<a class="btn btn-primary">`), so they
34+
// match this rule too. `.btn-primary`'s own `color` is only (0,1,0)
35+
// against this selector's (1,4,1), so without the exclusion the label
36+
// painted brand link-blue on the green button — #005dd5 on #1f883d is
37+
// 1.31:1, well under the 4.5:1 WCAG AA floor
38+
// (github/technical-content#7679). Excluding `.btn`
39+
// hands every button variant back to its own Primer colour tokens.
40+
a[href]:not(.heading-link):not(.btn) {
3341
// Fallback literals are brand's LIGHT values, not Primer's.
3442
color: var(--brand-color-text-link-rest, #005dd5);
3543

0 commit comments

Comments
 (0)