scope release-notes scss to component and reduce custom styles (#20847)
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react'
|
import { SyntheticEvent, useState } from 'react'
|
||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
import { ChevronDownIcon } from '@primer/octicons-react'
|
import { ChevronDownIcon } from '@primer/octicons-react'
|
||||||
import { GHAEReleaseNotePatch } from './GHAEReleaseNotePatch'
|
import { GHAEReleaseNotePatch } from './GHAEReleaseNotePatch'
|
||||||
@@ -40,12 +40,43 @@ export function GHAEReleaseNotes({ context }: GitHubAEProps) {
|
|||||||
<nav className="height-full overflow-auto">
|
<nav className="height-full overflow-auto">
|
||||||
<ul className="list-style-none pl-0 text-bold">
|
<ul className="list-style-none pl-0 text-bold">
|
||||||
{releases.map((release) => {
|
{releases.map((release) => {
|
||||||
|
return (
|
||||||
|
<CollapsibleReleaseSection
|
||||||
|
key={release.version}
|
||||||
|
release={release}
|
||||||
|
focusedPatch={focusedPatch}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const CollapsibleReleaseSection = ({
|
||||||
|
release,
|
||||||
|
focusedPatch,
|
||||||
|
}: {
|
||||||
|
release: GHAEReleaseNotesContextT['releases'][0]
|
||||||
|
focusedPatch: string
|
||||||
|
}) => {
|
||||||
|
const defaultIsOpen = true
|
||||||
|
const [isOpen, setIsOpen] = useState(defaultIsOpen)
|
||||||
|
|
||||||
|
const onToggle = (e: SyntheticEvent) => {
|
||||||
|
const newIsOpen = (e.target as HTMLDetailsElement).open
|
||||||
|
setIsOpen(newIsOpen)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={release.version} className="border-bottom">
|
<li key={release.version} className="border-bottom">
|
||||||
<details
|
<details
|
||||||
className="my-0 details-reset release-notes-version-picker"
|
className="my-0 details-reset release-notes-version-picker"
|
||||||
aria-current="page"
|
aria-current="page"
|
||||||
open
|
open={defaultIsOpen}
|
||||||
|
onToggle={onToggle}
|
||||||
>
|
>
|
||||||
<summary className="px-3 py-4 my-0 d-flex flex-items-center flex-justify-between">
|
<summary className="px-3 py-4 my-0 d-flex flex-items-center flex-justify-between">
|
||||||
{release.version}
|
{release.version}
|
||||||
@@ -53,20 +84,14 @@ export function GHAEReleaseNotes({ context }: GitHubAEProps) {
|
|||||||
<span className="color-text-tertiary text-mono text-small text-normal mr-1">
|
<span className="color-text-tertiary text-mono text-small text-normal mr-1">
|
||||||
{release.patches.length} releases
|
{release.patches.length} releases
|
||||||
</span>
|
</span>
|
||||||
<ChevronDownIcon />
|
<ChevronDownIcon className={isOpen ? 'rotate-180' : ''} />
|
||||||
</div>
|
</div>
|
||||||
</summary>
|
</summary>
|
||||||
<ul className="color-bg-tertiary border-top list-style-none py-4 px-0 my-0">
|
<ul className="color-bg-tertiary border-top list-style-none py-4 px-0 my-0">
|
||||||
{release.patches.map((patch) => {
|
{release.patches.map((patch) => {
|
||||||
const isActive = patch.version === focusedPatch
|
const isActive = patch.version === focusedPatch
|
||||||
return (
|
return (
|
||||||
<li
|
<li key={patch.version} className={cx('px-3 my-0 py-1', isActive && 'color-bg-info')}>
|
||||||
key={patch.version}
|
|
||||||
className={cx(
|
|
||||||
'js-release-notes-patch-link px-3 my-0 py-1',
|
|
||||||
isActive && 'selected'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<a
|
<a
|
||||||
href={`#${patch.date}`}
|
href={`#${patch.date}`}
|
||||||
className="d-flex flex-items-center flex-justify-between"
|
className="d-flex flex-items-center flex-justify-between"
|
||||||
@@ -80,10 +105,4 @@ export function GHAEReleaseNotes({ context }: GitHubAEProps) {
|
|||||||
</details>
|
</details>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</aside>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react'
|
import { SyntheticEvent, useState } from 'react'
|
||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
import {
|
import {
|
||||||
ChevronDownIcon,
|
ChevronDownIcon,
|
||||||
@@ -103,47 +103,12 @@ export function GHESReleaseNotes({ context }: Props) {
|
|||||||
|
|
||||||
if (release.version === currentVersion.currentRelease) {
|
if (release.version === currentVersion.currentRelease) {
|
||||||
return (
|
return (
|
||||||
<li key={release.version} className="border-bottom">
|
<CollapsibleReleaseSection
|
||||||
<details
|
key={release.version}
|
||||||
className="my-0 details-reset release-notes-version-picker"
|
release={release}
|
||||||
aria-current="page"
|
focusedPatch={focusedPatch}
|
||||||
open
|
releaseLink={releaseLink}
|
||||||
>
|
/>
|
||||||
<summary className="px-3 py-4 my-0 d-flex flex-items-center flex-justify-between">
|
|
||||||
{release.version}
|
|
||||||
<div className="d-flex">
|
|
||||||
<span className="color-text-tertiary text-mono text-small text-normal mr-1">
|
|
||||||
{release.patches.length} releases
|
|
||||||
</span>
|
|
||||||
<ChevronDownIcon />
|
|
||||||
</div>
|
|
||||||
</summary>
|
|
||||||
<ul className="color-bg-tertiary border-top list-style-none py-4 px-0 my-0">
|
|
||||||
{release.patches.map((patch) => {
|
|
||||||
const isActive = patch.version === focusedPatch
|
|
||||||
return (
|
|
||||||
<li
|
|
||||||
key={patch.version}
|
|
||||||
className={cx(
|
|
||||||
'js-release-notes-patch-link px-3 my-0 py-1',
|
|
||||||
isActive && 'selected'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Link
|
|
||||||
href={`${releaseLink}#${patch.version}`}
|
|
||||||
className="d-flex flex-items-center flex-justify-between"
|
|
||||||
>
|
|
||||||
{patch.version}
|
|
||||||
<span className="color-text-tertiary text-mono text-small text-normal">
|
|
||||||
{dayjs(patch.date).format('MMMM DD, YYYY')}
|
|
||||||
</span>
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</details>
|
|
||||||
</li>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,3 +132,59 @@ export function GHESReleaseNotes({ context }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CollapsibleReleaseSection = ({
|
||||||
|
release,
|
||||||
|
releaseLink,
|
||||||
|
focusedPatch,
|
||||||
|
}: {
|
||||||
|
release: GHESReleaseNotesContextT['releases'][0]
|
||||||
|
releaseLink: string
|
||||||
|
focusedPatch: string
|
||||||
|
}) => {
|
||||||
|
const defaultIsOpen = true
|
||||||
|
const [isOpen, setIsOpen] = useState(defaultIsOpen)
|
||||||
|
|
||||||
|
const onToggle = (e: SyntheticEvent) => {
|
||||||
|
const newIsOpen = (e.target as HTMLDetailsElement).open
|
||||||
|
setIsOpen(newIsOpen)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<li key={release.version} className="border-bottom">
|
||||||
|
<details
|
||||||
|
className="my-0 details-reset release-notes-version-picker"
|
||||||
|
aria-current="page"
|
||||||
|
open={defaultIsOpen}
|
||||||
|
onToggle={onToggle}
|
||||||
|
>
|
||||||
|
<summary className="px-3 py-4 my-0 d-flex flex-items-center flex-justify-between">
|
||||||
|
{release.version}
|
||||||
|
<div className="d-flex">
|
||||||
|
<span className="color-text-tertiary text-mono text-small text-normal mr-1">
|
||||||
|
{release.patches.length} releases
|
||||||
|
</span>
|
||||||
|
<ChevronDownIcon className={isOpen ? 'rotate-180' : ''} />
|
||||||
|
</div>
|
||||||
|
</summary>
|
||||||
|
<ul className="color-bg-tertiary border-top list-style-none py-4 px-0 my-0">
|
||||||
|
{release.patches.map((patch) => {
|
||||||
|
const isActive = patch.version === focusedPatch
|
||||||
|
return (
|
||||||
|
<li key={patch.version} className={cx('px-3 my-0 py-1', isActive && 'color-bg-info')}>
|
||||||
|
<Link
|
||||||
|
href={`${releaseLink}#${patch.version}`}
|
||||||
|
className="d-flex flex-items-center flex-justify-between"
|
||||||
|
>
|
||||||
|
{patch.version}
|
||||||
|
<span className="color-text-tertiary text-mono text-small text-normal">
|
||||||
|
{dayjs(patch.date).format('MMMM DD, YYYY')}
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
8
components/release-notes/PatchNotes.module.scss
Normal file
8
components/release-notes/PatchNotes.module.scss
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
@import "@primer/css/layout/index.scss";
|
||||||
|
|
||||||
|
.sectionHeading {
|
||||||
|
scroll-margin-top: 280px !important;
|
||||||
|
@include breakpoint(sm) {
|
||||||
|
scroll-margin-top: 200px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ import slugger from 'github-slugger'
|
|||||||
import { ReleaseNotePatch } from './types'
|
import { ReleaseNotePatch } from './types'
|
||||||
import { Link } from 'components/Link'
|
import { Link } from 'components/Link'
|
||||||
|
|
||||||
|
import styles from './PatchNotes.module.scss'
|
||||||
|
|
||||||
const SectionToLabelMap: Record<string, string> = {
|
const SectionToLabelMap: Record<string, string> = {
|
||||||
features: 'Features',
|
features: 'Features',
|
||||||
bugs: 'Bug fixes',
|
bugs: 'Bug fixes',
|
||||||
@@ -13,6 +15,16 @@ const SectionToLabelMap: Record<string, string> = {
|
|||||||
backups: 'Backups',
|
backups: 'Backups',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ColorMap = {
|
||||||
|
features: 'var(--color-auto-green-5)',
|
||||||
|
bugs: 'var(--color-auto-yellow-5)',
|
||||||
|
known_issues: 'var(--color-auto-blue-5)',
|
||||||
|
security_fixes: 'var(--color-auto-pink-5)',
|
||||||
|
changes: 'var(--color-auto-green-5)',
|
||||||
|
deprecations: 'var(--color-auto-purple-5)',
|
||||||
|
backups: 'var(--color-auto-orange-5)',
|
||||||
|
}
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
patch: ReleaseNotePatch
|
patch: ReleaseNotePatch
|
||||||
withReleaseNoteLabel?: boolean
|
withReleaseNoteLabel?: boolean
|
||||||
@@ -22,11 +34,11 @@ export function PatchNotes({ patch, withReleaseNoteLabel }: Props) {
|
|||||||
<>
|
<>
|
||||||
{Object.entries(patch.sections).map(([key, sectionItems], i, arr) => {
|
{Object.entries(patch.sections).map(([key, sectionItems], i, arr) => {
|
||||||
const isLast = i === arr.length - 1
|
const isLast = i === arr.length - 1
|
||||||
|
const primaryColor = ColorMap[key as keyof typeof ColorMap] || ColorMap.features
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={key}
|
key={key}
|
||||||
className={cx(
|
className={cx(
|
||||||
`release-notes-section-${key}`,
|
|
||||||
'py-6 d-block d-xl-flex gutter-xl flex-items-baseline',
|
'py-6 d-block d-xl-flex gutter-xl flex-items-baseline',
|
||||||
!withReleaseNoteLabel && 'mx-6',
|
!withReleaseNoteLabel && 'mx-6',
|
||||||
!isLast && 'border-bottom'
|
!isLast && 'border-bottom'
|
||||||
@@ -34,41 +46,39 @@ export function PatchNotes({ patch, withReleaseNoteLabel }: Props) {
|
|||||||
>
|
>
|
||||||
{withReleaseNoteLabel && (
|
{withReleaseNoteLabel && (
|
||||||
<div className="col-12 col-xl-3 mb-5">
|
<div className="col-12 col-xl-3 mb-5">
|
||||||
<span className="px-3 py-2 text-small text-bold text-uppercase text-mono color-text-inverse release-notes-section-label">
|
<span
|
||||||
|
className="px-3 py-2 text-small text-bold text-uppercase text-mono color-text-inverse"
|
||||||
|
style={{ backgroundColor: primaryColor }}
|
||||||
|
>
|
||||||
{SectionToLabelMap[key] || 'INVALID SECTION'}
|
{SectionToLabelMap[key] || 'INVALID SECTION'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<ul className={cx(withReleaseNoteLabel && 'col-xl-9', 'col-12 release-notes-list')}>
|
<ul className={cx(withReleaseNoteLabel && 'col-xl-9', 'col-12')}>
|
||||||
{sectionItems.map((item) => {
|
{sectionItems.map((item) => {
|
||||||
if (typeof item === 'string') {
|
if (typeof item === 'string') {
|
||||||
return (
|
return <li key={item} className="f4" dangerouslySetInnerHTML={{ __html: item }} />
|
||||||
<li
|
|
||||||
key={item}
|
|
||||||
className="release-notes-list-item"
|
|
||||||
dangerouslySetInnerHTML={{ __html: item }}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const slug = item.heading ? slugger.slug(item.heading) : ''
|
const slug = item.heading ? slugger.slug(item.heading) : ''
|
||||||
return (
|
return (
|
||||||
<li key={slug} className="release-notes-list-item list-style-none">
|
<li key={slug} className="list-style-none">
|
||||||
<h4
|
<h4
|
||||||
id={slug}
|
id={slug}
|
||||||
className="release-notes-section-heading text-uppercase text-bold"
|
className={cx(styles.sectionHeading, 'text-uppercase text-bold f4')}
|
||||||
|
style={{ color: !withReleaseNoteLabel ? primaryColor : '' }}
|
||||||
>
|
>
|
||||||
<Link href={`#${slug}`} className="text-inherit">
|
<Link href={`#${slug}`} className="text-inherit">
|
||||||
{item.heading}
|
{item.heading}
|
||||||
</Link>
|
</Link>
|
||||||
</h4>
|
</h4>
|
||||||
|
|
||||||
<ul className="pl-0 pb-4 mt-2 release-notes-list">
|
<ul className="pl-0 pb-4 mt-2">
|
||||||
{item.notes.map((note) => {
|
{item.notes.map((note) => {
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
key={note}
|
key={note}
|
||||||
className="release-notes-list-item"
|
className="list-style-none f4"
|
||||||
dangerouslySetInnerHTML={{ __html: note }}
|
dangerouslySetInnerHTML={{ __html: note }}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ $marketing-font-path: "/assets/fonts/inter/";
|
|||||||
@import "images.scss";
|
@import "images.scss";
|
||||||
@import "lists.scss";
|
@import "lists.scss";
|
||||||
@import "product-sublanding.scss";
|
@import "product-sublanding.scss";
|
||||||
@import "release-notes.scss";
|
|
||||||
@import "search.scss";
|
@import "search.scss";
|
||||||
@import "shadows.scss";
|
@import "shadows.scss";
|
||||||
@import "summary.scss";
|
@import "summary.scss";
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
ul.release-notes-list li.release-notes-list-item {
|
|
||||||
font-size: 15px !important;
|
|
||||||
|
|
||||||
&::marker {
|
|
||||||
// `• `
|
|
||||||
content: "\2022\00a0\00a0\00a0\00a0";
|
|
||||||
font-size: 1.6em;
|
|
||||||
color: var(--color-auto-gray-4);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.list-style-none::marker {
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-notes-section-heading {
|
|
||||||
font-size: 15px !important;
|
|
||||||
scroll-margin-top: 280px !important;
|
|
||||||
@include breakpoint(sm) {
|
|
||||||
scroll-margin-top: 200px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
details[open].release-notes-version-picker
|
|
||||||
summary
|
|
||||||
.octicon.octicon-chevron-down {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-release-notes-patch-link {
|
|
||||||
&.selected {
|
|
||||||
background-color: var(--color-auto-blue-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$colors-list: (
|
|
||||||
features: var(--color-auto-green-5),
|
|
||||||
bugs: var(--color-auto-yellow-5),
|
|
||||||
known_issues: var(--color-auto-blue-5),
|
|
||||||
security_fixes: var(--color-auto-pink-5),
|
|
||||||
changes: var(--color-auto-green-5),
|
|
||||||
deprecations: var(--color-auto-purple-5),
|
|
||||||
backups: var(--color-auto-orange-5),
|
|
||||||
);
|
|
||||||
|
|
||||||
@each $key, $val in $colors-list {
|
|
||||||
.release-notes-section-#{$key} {
|
|
||||||
.release-notes-section-label {
|
|
||||||
background-color: #{$val};
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-notes-section-heading {
|
|
||||||
color: #{$val};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user