Migrate Callout React component to Alert (#47226)
Co-authored-by: Peter Bengtsson <peterbe@github.com>
This commit is contained in:
@@ -245,3 +245,9 @@ scroll_button:
|
|||||||
popovers:
|
popovers:
|
||||||
role_description: hover card
|
role_description: hover card
|
||||||
keyboard_shortcut_description: Press alt+up to activate
|
keyboard_shortcut_description: Press alt+up to activate
|
||||||
|
alerts:
|
||||||
|
NOTE: Note
|
||||||
|
IMPORTANT: Important
|
||||||
|
WARNING: Warning
|
||||||
|
TIP: Tip
|
||||||
|
CAUTION: Caution
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { ArticleGridLayout } from 'src/frame/components/article/ArticleGridLayou
|
|||||||
import { MiniTocs } from 'src/frame/components/ui/MiniTocs'
|
import { MiniTocs } from 'src/frame/components/ui/MiniTocs'
|
||||||
import { useAutomatedPageContext } from 'src/automated-pipelines/components/AutomatedPageContext'
|
import { useAutomatedPageContext } from 'src/automated-pipelines/components/AutomatedPageContext'
|
||||||
import { ClientSideHighlight } from 'src/frame/components/ClientSideHighlight'
|
import { ClientSideHighlight } from 'src/frame/components/ClientSideHighlight'
|
||||||
import { Callout } from 'src/frame/components/ui/Callout'
|
import { Alert } from 'src/frame/components/ui/Alert'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
@@ -34,9 +34,7 @@ export const AutomatedPage = ({ children }: Props) => {
|
|||||||
|
|
||||||
{permissions && <PermissionsStatement permissions={permissions} />}
|
{permissions && <PermissionsStatement permissions={permissions} />}
|
||||||
|
|
||||||
{product && (
|
{product && <Alert className="mb-4" html={product} />}
|
||||||
<Callout className="mb-4" dangerouslySetInnerHTML={{ __html: product }} />
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
toc={miniTocItems.length > 1 && <MiniTocs miniTocItems={miniTocItems} />}
|
toc={miniTocItems.length > 1 && <MiniTocs miniTocItems={miniTocItems} />}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export const tags = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const template =
|
const template =
|
||||||
'<div class="ghd-spotlight ghd-spotlight-{{ color }} my-4 pl-3 py-2">{{ output }}</div>'
|
'<div class="ghd-alert ghd-alert-{{ color }} ghd-spotlight-{{ color }}">{{ output }}</div>'
|
||||||
|
|
||||||
export const Spotlight = {
|
export const Spotlight = {
|
||||||
type: 'block',
|
type: 'block',
|
||||||
|
|||||||
@@ -11,10 +11,15 @@ $colors: "default", "muted", "subtle", "accent", "success", "attention",
|
|||||||
border-left: 0.25em solid
|
border-left: 0.25em solid
|
||||||
var(--borderColor-default, var(--color-border-default));
|
var(--borderColor-default, var(--color-border-default));
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
|
||||||
|
|
||||||
.ghd-alert > :last-child {
|
> :last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background: transparent;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ghd-alert-title {
|
.ghd-alert-title {
|
||||||
@@ -32,4 +37,15 @@ $colors: "default", "muted", "subtle", "accent", "success", "attention",
|
|||||||
color: var(--fgColor-#{$color}, var(--color-#{$color}-fg));
|
color: var(--fgColor-#{$color}, var(--color-#{$color}-fg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Temporary: so that the existing "notes" "callouts" etc color the first word
|
||||||
|
.ghd-spotlight-#{$color} {
|
||||||
|
p:first-child {
|
||||||
|
strong:first-child,
|
||||||
|
b:first-child {
|
||||||
|
color: var(--fgColor-#{$color}, var(--color-#{$color}-fg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End temporary
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,5 @@
|
|||||||
@import "heading-links.scss";
|
@import "heading-links.scss";
|
||||||
@import "images.scss";
|
@import "images.scss";
|
||||||
@import "markdown-overrides.scss";
|
@import "markdown-overrides.scss";
|
||||||
@import "spotlight.scss";
|
|
||||||
@import "syntax-highlighting.scss";
|
@import "syntax-highlighting.scss";
|
||||||
@import "alerts.scss";
|
@import "alerts.scss";
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
.ghd-spotlight {
|
|
||||||
border-left: 0.25rem solid;
|
|
||||||
|
|
||||||
:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
background: transparent;
|
|
||||||
padding: 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$colors: "default", "muted", "subtle", "accent", "success", "attention",
|
|
||||||
"severe", "danger", "open", "closed", "done", "sponsors";
|
|
||||||
|
|
||||||
@each $color in $colors {
|
|
||||||
.ghd-spotlight-#{$color} {
|
|
||||||
border-left-color: var(--fgColor-#{$color}, var(--color-#{$color}-fg));
|
|
||||||
|
|
||||||
p:first-child strong:first-child,
|
|
||||||
b:first-child {
|
|
||||||
color: var(--fgColor-#{$color}, var(--color-#{$color}-fg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -245,3 +245,9 @@ scroll_button:
|
|||||||
popovers:
|
popovers:
|
||||||
role_description: hover card
|
role_description: hover card
|
||||||
keyboard_shortcut_description: Press alt+up to activate
|
keyboard_shortcut_description: Press alt+up to activate
|
||||||
|
alerts:
|
||||||
|
NOTE: Note
|
||||||
|
IMPORTANT: Important
|
||||||
|
WARNING: Warning
|
||||||
|
TIP: Tip
|
||||||
|
CAUTION: Caution
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
import { getDOM } from '#src/tests/helpers/e2etest.js'
|
||||||
|
|
||||||
describe('callouts', () => {
|
describe('alerts', () => {
|
||||||
test('article page', async () => {
|
test('article page', async () => {
|
||||||
const $ = await getDOM('/get-started/foo/page-with-callout')
|
const $ = await getDOM('/get-started/foo/page-with-callout')
|
||||||
const callout = $('[data-testid=callout]')
|
const callout = $('[data-testid=alert] div')
|
||||||
expect(callout.html()).toBe('<p>Callout for HubGit Pages</p>')
|
expect(callout.html()).toBe('<p>Callout for HubGit Pages</p>')
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -11,16 +11,16 @@ describe('callouts', () => {
|
|||||||
// This page has `product:` property which is a piece of Liquid
|
// This page has `product:` property which is a piece of Liquid
|
||||||
// which makes it so that the rendered output of that becomes
|
// which makes it so that the rendered output of that becomes
|
||||||
// an empty string.
|
// an empty string.
|
||||||
// This test tests that callout is not rendered if its output
|
// This test tests that alert is not rendered if its output
|
||||||
// "exits" but is empty.
|
// "exits" but is empty.
|
||||||
const $ = await getDOM('/enterprise-server@latest/get-started/foo/page-with-callout')
|
const $ = await getDOM('/enterprise-server@latest/get-started/foo/page-with-callout')
|
||||||
const callout = $('[data-testid=callout]')
|
const callout = $('[data-testid=alert]')
|
||||||
expect(callout.length).toBe(0)
|
expect(callout.length).toBe(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('toc landing page', async () => {
|
test('toc landing page', async () => {
|
||||||
const $ = await getDOM('/actions/category')
|
const $ = await getDOM('/actions/category')
|
||||||
const callout = $('[data-testid=callout]')
|
const callout = $('[data-testid=alert] div')
|
||||||
expect(callout.html()).toBe('<p>This is the callout text</p>')
|
expect(callout.html()).toBe('<p>This is the callout text</p>')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -3,7 +3,7 @@ import dynamic from 'next/dynamic'
|
|||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
import { LinkExternalIcon } from '@primer/octicons-react'
|
import { LinkExternalIcon } from '@primer/octicons-react'
|
||||||
|
|
||||||
import { Callout } from 'src/frame/components/ui/Callout'
|
import { Alert } from 'src/frame/components/ui/Alert'
|
||||||
import { DefaultLayout } from 'src/frame/components/DefaultLayout'
|
import { DefaultLayout } from 'src/frame/components/DefaultLayout'
|
||||||
import { ArticleTitle } from 'src/frame/components/article/ArticleTitle'
|
import { ArticleTitle } from 'src/frame/components/article/ArticleTitle'
|
||||||
import { useArticleContext } from 'src/frame/components/context/ArticleContext'
|
import { useArticleContext } from 'src/frame/components/context/ArticleContext'
|
||||||
@@ -63,7 +63,7 @@ export const ArticlePage = () => {
|
|||||||
{includesPlatformSpecificContent && <PlatformPicker />}
|
{includesPlatformSpecificContent && <PlatformPicker />}
|
||||||
{includesToolSpecificContent && <ToolPicker />}
|
{includesToolSpecificContent && <ToolPicker />}
|
||||||
|
|
||||||
{product && <Callout className="mb-4" dangerouslySetInnerHTML={{ __html: product }} />}
|
{product && <Alert className="mb-4" html={product} />}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ export type MainContextT = {
|
|||||||
// they will always be available and don't need to be manually added.
|
// they will always be available and don't need to be manually added.
|
||||||
// Order does not matter on these.
|
// Order does not matter on these.
|
||||||
const DEFAULT_UI_NAMESPACES = [
|
const DEFAULT_UI_NAMESPACES = [
|
||||||
|
'alerts',
|
||||||
'header',
|
'header',
|
||||||
'search',
|
'search',
|
||||||
'survey',
|
'survey',
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
.container {
|
.container {
|
||||||
p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
a {
|
a {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
37
src/frame/components/ui/Alert/Alert.tsx
Normal file
37
src/frame/components/ui/Alert/Alert.tsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { createElement, ReactNode } from 'react'
|
||||||
|
import cx from 'classnames'
|
||||||
|
import styles from './Alert.module.scss'
|
||||||
|
import { InfoIcon, ReportIcon, AlertIcon, LightBulbIcon, StopIcon } from '@primer/octicons-react'
|
||||||
|
import { useTranslation } from 'src/languages/components/useTranslation'
|
||||||
|
|
||||||
|
const alertTypes = {
|
||||||
|
NOTE: { icon: InfoIcon, color: 'accent' },
|
||||||
|
IMPORTANT: { icon: ReportIcon, color: 'done' },
|
||||||
|
WARNING: { icon: AlertIcon, color: 'attention' },
|
||||||
|
TIP: { icon: LightBulbIcon, color: 'success' },
|
||||||
|
CAUTION: { icon: StopIcon, color: 'danger' },
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AlertPropsT = {
|
||||||
|
html?: string
|
||||||
|
children?: ReactNode
|
||||||
|
className?: string
|
||||||
|
type?: keyof typeof alertTypes
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Alert({ className, html, children, type = 'IMPORTANT' }: AlertPropsT) {
|
||||||
|
if (html && children) throw new Error("Can't specify 'html' and 'children'")
|
||||||
|
const { t } = useTranslation('alerts')
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-testid="alert"
|
||||||
|
className={cx(className, styles.container, `ghd-alert ghd-alert-${alertTypes[type].color}`)}
|
||||||
|
>
|
||||||
|
<p className="ghd-alert-title">
|
||||||
|
{createElement(alertTypes[type].icon, { size: 16, className: 'mr-2' })}
|
||||||
|
{t(type)}
|
||||||
|
</p>
|
||||||
|
{html ? <div dangerouslySetInnerHTML={{ __html: html }} /> : children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
1
src/frame/components/ui/Alert/index.ts
Normal file
1
src/frame/components/ui/Alert/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export { Alert } from './Alert'
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import { DOMAttributes, ReactNode } from 'react'
|
|
||||||
import cx from 'classnames'
|
|
||||||
import styles from './Callout.module.scss'
|
|
||||||
|
|
||||||
export type CalloutPropsT = {
|
|
||||||
dangerouslySetInnerHTML?: DOMAttributes<HTMLDivElement>['dangerouslySetInnerHTML']
|
|
||||||
children?: ReactNode
|
|
||||||
className?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Callout = ({ className, dangerouslySetInnerHTML, children }: CalloutPropsT) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
data-testid="callout"
|
|
||||||
className={cx(className, styles.container, 'ghd-spotlight ghd-spotlight-done my-4 pl-3 py-2')}
|
|
||||||
dangerouslySetInnerHTML={dangerouslySetInnerHTML}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { Callout } from './Callout'
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Link } from 'src/frame/components/Link'
|
import { Link } from 'src/frame/components/Link'
|
||||||
|
import { Alert } from 'src/frame/components/ui/Alert'
|
||||||
import { useTranslation } from 'src/languages/components/useTranslation'
|
import { useTranslation } from 'src/languages/components/useTranslation'
|
||||||
import type { GraphqlT } from './types'
|
import type { GraphqlT } from './types'
|
||||||
|
|
||||||
@@ -9,14 +10,8 @@ type Props = {
|
|||||||
|
|
||||||
export function Notice({ item, variant = 'preview' }: Props) {
|
export function Notice({ item, variant = 'preview' }: Props) {
|
||||||
const { t } = useTranslation('graphql')
|
const { t } = useTranslation('graphql')
|
||||||
const previewTitle =
|
|
||||||
variant === 'preview' ? t('reference.preview_notice') : t('reference.deprecation_notice')
|
|
||||||
const noticeStyle = variant === 'preview' ? 'ghd-spotlight-accent' : 'ghd-spotlight-attention'
|
|
||||||
return (
|
return (
|
||||||
<div className={`ghd-spotlight ${noticeStyle} my-4 pl-3 py-2`}>
|
<Alert type={variant === 'preview' ? 'NOTE' : 'WARNING'}>
|
||||||
<p>
|
|
||||||
<b>{previewTitle}</b>
|
|
||||||
</p>
|
|
||||||
{variant === 'preview' && item.preview ? (
|
{variant === 'preview' && item.preview ? (
|
||||||
<p>
|
<p>
|
||||||
<code>{item.name}</code> is available under the{' '}
|
<code>{item.name}</code> is available under the{' '}
|
||||||
@@ -37,6 +32,6 @@ export function Notice({ item, variant = 'preview' }: Props) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</Alert>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { ArticleTitle } from 'src/frame/components/article/ArticleTitle'
|
|||||||
import { MarkdownContent } from 'src/frame/components/ui/MarkdownContent'
|
import { MarkdownContent } from 'src/frame/components/ui/MarkdownContent'
|
||||||
import { ArticleList } from 'src/landings/components/ArticleList'
|
import { ArticleList } from 'src/landings/components/ArticleList'
|
||||||
import { ArticleGridLayout } from 'src/frame/components/article/ArticleGridLayout'
|
import { ArticleGridLayout } from 'src/frame/components/article/ArticleGridLayout'
|
||||||
import { Callout } from 'src/frame/components/ui/Callout'
|
import { Alert } from 'src/frame/components/ui/Alert'
|
||||||
import { Lead } from 'src/frame/components/ui/Lead'
|
import { Lead } from 'src/frame/components/ui/Lead'
|
||||||
import { LearningTrackNav } from 'src/learning-track/components/article/LearningTrackNav'
|
import { LearningTrackNav } from 'src/learning-track/components/article/LearningTrackNav'
|
||||||
import { ClientSideRedirects } from 'src/rest/components/ClientSideRedirects'
|
import { ClientSideRedirects } from 'src/rest/components/ClientSideRedirects'
|
||||||
@@ -46,7 +46,7 @@ export const TocLanding = () => {
|
|||||||
|
|
||||||
{intro && <Lead data-search="lead">{intro}</Lead>}
|
{intro && <Lead data-search="lead">{intro}</Lead>}
|
||||||
|
|
||||||
{productCallout && <Callout dangerouslySetInnerHTML={{ __html: productCallout }} />}
|
{productCallout && <Alert html={productCallout} />}
|
||||||
|
|
||||||
<div className="border-bottom border-xl-0 pb-4 mb-5 pb-xl-2 mb-xl-2" />
|
<div className="border-bottom border-xl-0 pb-4 mb-5 pb-xl-2 mb-xl-2" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Alert } from 'src/frame/components/ui/Alert'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
slug: string
|
slug: string
|
||||||
previews: Array<string>
|
previews: Array<string>
|
||||||
@@ -11,11 +13,7 @@ export function RestPreviewNotice({ slug, previews, heading }: Props) {
|
|||||||
<a href={`#${slug}-preview-notices`}>{heading}</a>
|
<a href={`#${slug}-preview-notices`}>{heading}</a>
|
||||||
</h3>
|
</h3>
|
||||||
{previews.map((preview, index) => (
|
{previews.map((preview, index) => (
|
||||||
<div
|
<Alert type="NOTE" html={preview} key={JSON.stringify(preview) + index} />
|
||||||
className="ghd-spotlight ghd-spotlight-accent my-4 pl-3 py-2"
|
|
||||||
dangerouslySetInnerHTML={{ __html: preview }}
|
|
||||||
key={JSON.stringify(preview) + index}
|
|
||||||
/>
|
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user