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:
|
||||
role_description: hover card
|
||||
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 { useAutomatedPageContext } from 'src/automated-pipelines/components/AutomatedPageContext'
|
||||
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 = {
|
||||
children: React.ReactNode
|
||||
@@ -34,9 +34,7 @@ export const AutomatedPage = ({ children }: Props) => {
|
||||
|
||||
{permissions && <PermissionsStatement permissions={permissions} />}
|
||||
|
||||
{product && (
|
||||
<Callout className="mb-4" dangerouslySetInnerHTML={{ __html: product }} />
|
||||
)}
|
||||
{product && <Alert className="mb-4" html={product} />}
|
||||
</>
|
||||
}
|
||||
toc={miniTocItems.length > 1 && <MiniTocs miniTocItems={miniTocItems} />}
|
||||
|
||||
@@ -6,7 +6,7 @@ export const tags = {
|
||||
}
|
||||
|
||||
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 = {
|
||||
type: 'block',
|
||||
|
||||
@@ -11,10 +11,15 @@ $colors: "default", "muted", "subtle", "accent", "success", "attention",
|
||||
border-left: 0.25em solid
|
||||
var(--borderColor-default, var(--color-border-default));
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.ghd-alert > :last-child {
|
||||
margin-bottom: 0;
|
||||
> :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: transparent;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.ghd-alert-title {
|
||||
@@ -32,4 +37,15 @@ $colors: "default", "muted", "subtle", "accent", "success", "attention",
|
||||
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 "images.scss";
|
||||
@import "markdown-overrides.scss";
|
||||
@import "spotlight.scss";
|
||||
@import "syntax-highlighting.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:
|
||||
role_description: hover card
|
||||
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'
|
||||
|
||||
describe('callouts', () => {
|
||||
describe('alerts', () => {
|
||||
test('article page', async () => {
|
||||
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>')
|
||||
})
|
||||
|
||||
@@ -11,16 +11,16 @@ describe('callouts', () => {
|
||||
// This page has `product:` property which is a piece of Liquid
|
||||
// which makes it so that the rendered output of that becomes
|
||||
// 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.
|
||||
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)
|
||||
})
|
||||
|
||||
test('toc landing page', async () => {
|
||||
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>')
|
||||
})
|
||||
})
|
||||
@@ -3,7 +3,7 @@ import dynamic from 'next/dynamic'
|
||||
import cx from 'classnames'
|
||||
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 { ArticleTitle } from 'src/frame/components/article/ArticleTitle'
|
||||
import { useArticleContext } from 'src/frame/components/context/ArticleContext'
|
||||
@@ -63,7 +63,7 @@ export const ArticlePage = () => {
|
||||
{includesPlatformSpecificContent && <PlatformPicker />}
|
||||
{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.
|
||||
// Order does not matter on these.
|
||||
const DEFAULT_UI_NAMESPACES = [
|
||||
'alerts',
|
||||
'header',
|
||||
'search',
|
||||
'survey',
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
.container {
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
a {
|
||||
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 { Alert } from 'src/frame/components/ui/Alert'
|
||||
import { useTranslation } from 'src/languages/components/useTranslation'
|
||||
import type { GraphqlT } from './types'
|
||||
|
||||
@@ -9,14 +10,8 @@ type Props = {
|
||||
|
||||
export function Notice({ item, variant = 'preview' }: Props) {
|
||||
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 (
|
||||
<div className={`ghd-spotlight ${noticeStyle} my-4 pl-3 py-2`}>
|
||||
<p>
|
||||
<b>{previewTitle}</b>
|
||||
</p>
|
||||
<Alert type={variant === 'preview' ? 'NOTE' : 'WARNING'}>
|
||||
{variant === 'preview' && item.preview ? (
|
||||
<p>
|
||||
<code>{item.name}</code> is available under the{' '}
|
||||
@@ -37,6 +32,6 @@ export function Notice({ item, variant = 'preview' }: Props) {
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</Alert>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ArticleTitle } from 'src/frame/components/article/ArticleTitle'
|
||||
import { MarkdownContent } from 'src/frame/components/ui/MarkdownContent'
|
||||
import { ArticleList } from 'src/landings/components/ArticleList'
|
||||
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 { LearningTrackNav } from 'src/learning-track/components/article/LearningTrackNav'
|
||||
import { ClientSideRedirects } from 'src/rest/components/ClientSideRedirects'
|
||||
@@ -46,7 +46,7 @@ export const TocLanding = () => {
|
||||
|
||||
{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" />
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Alert } from 'src/frame/components/ui/Alert'
|
||||
|
||||
type Props = {
|
||||
slug: string
|
||||
previews: Array<string>
|
||||
@@ -11,11 +13,7 @@ export function RestPreviewNotice({ slug, previews, heading }: Props) {
|
||||
<a href={`#${slug}-preview-notices`}>{heading}</a>
|
||||
</h3>
|
||||
{previews.map((preview, index) => (
|
||||
<div
|
||||
className="ghd-spotlight ghd-spotlight-accent my-4 pl-3 py-2"
|
||||
dangerouslySetInnerHTML={{ __html: preview }}
|
||||
key={JSON.stringify(preview) + index}
|
||||
/>
|
||||
<Alert type="NOTE" html={preview} key={JSON.stringify(preview) + index} />
|
||||
))}
|
||||
</>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user