Replace sx and inline style declarations with CSS modules (#57848)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
16
src/audit-logs/components/GroupedEvents.module.scss
Normal file
16
src/audit-logs/components/GroupedEvents.module.scss
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
.eventItem {
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventAction {
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventDetail {
|
||||||
|
margin-left: 1rem;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eventDescription {
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ import { HeadingLink } from '@/frame/components/article/HeadingLink'
|
|||||||
import { useTranslation } from '@/languages/components/useTranslation'
|
import { useTranslation } from '@/languages/components/useTranslation'
|
||||||
import type { AuditLogEventT } from '../types'
|
import type { AuditLogEventT } from '../types'
|
||||||
|
|
||||||
|
import styles from './GroupedEvents.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
auditLogEvents: AuditLogEventT[]
|
auditLogEvents: AuditLogEventT[]
|
||||||
category: string
|
category: string
|
||||||
@@ -47,15 +49,15 @@ export default function GroupedEvents({ auditLogEvents, category, categoryNote }
|
|||||||
)}
|
)}
|
||||||
<div>
|
<div>
|
||||||
{auditLogEvents.map((event) => (
|
{auditLogEvents.map((event) => (
|
||||||
<div key={event.action} style={{ marginBottom: '3rem' }}>
|
<div key={event.action} className={styles.eventItem}>
|
||||||
<dl>
|
<dl>
|
||||||
<dt style={{ fontStyle: 'normal' }}>
|
<dt className={styles.eventAction}>
|
||||||
<code>{event.action}</code>
|
<code>{event.action}</code>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>{event.description}</dd>
|
<dd>{event.description}</dd>
|
||||||
|
|
||||||
<dt style={{ marginLeft: '1rem', fontStyle: 'normal' }}>{t('fields')}</dt>
|
<dt className={styles.eventDetail}>{t('fields')}</dt>
|
||||||
<dd style={{ marginLeft: '1rem' }}>
|
<dd className={styles.eventDescription}>
|
||||||
{event.fields
|
{event.fields
|
||||||
? event.fields.map((field, index) => (
|
? event.fields.map((field, index) => (
|
||||||
<span key={field}>
|
<span key={field}>
|
||||||
@@ -68,8 +70,8 @@ export default function GroupedEvents({ auditLogEvents, category, categoryNote }
|
|||||||
|
|
||||||
{event.docs_reference_links && event.docs_reference_links !== 'N/A' && (
|
{event.docs_reference_links && event.docs_reference_links !== 'N/A' && (
|
||||||
<>
|
<>
|
||||||
<dt style={{ marginLeft: '1rem', fontStyle: 'normal' }}>{t('reference')}</dt>
|
<dt className={styles.eventDetail}>{t('reference')}</dt>
|
||||||
<dd style={{ marginLeft: '1rem' }}>{renderReferenceLinks(event)}</dd>
|
<dd className={styles.eventDescription}>{renderReferenceLinks(event)}</dd>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</dl>
|
</dl>
|
||||||
|
|||||||
3
src/frame/components/DefaultLayout.module.scss
Normal file
3
src/frame/components/DefaultLayout.module.scss
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.mainContent {
|
||||||
|
scroll-margin-top: 5rem;
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@ import { useLanguages } from '@/languages/components/LanguagesContext'
|
|||||||
import { ClientSideLanguageRedirect } from './ClientSideLanguageRedirect'
|
import { ClientSideLanguageRedirect } from './ClientSideLanguageRedirect'
|
||||||
import { SearchOverlayContextProvider } from '@/search/components/context/SearchOverlayContext'
|
import { SearchOverlayContextProvider } from '@/search/components/context/SearchOverlayContext'
|
||||||
|
|
||||||
|
import styles from './DefaultLayout.module.scss'
|
||||||
|
|
||||||
const MINIMAL_RENDER = Boolean(JSON.parse(process.env.MINIMAL_RENDER || 'false'))
|
const MINIMAL_RENDER = Boolean(JSON.parse(process.env.MINIMAL_RENDER || 'false'))
|
||||||
|
|
||||||
type Props = { children?: React.ReactNode }
|
type Props = { children?: React.ReactNode }
|
||||||
@@ -51,7 +53,7 @@ export const DefaultLayout = (props: Props) => {
|
|||||||
<Breadcrumbs />
|
<Breadcrumbs />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<main id="main-content" style={{ scrollMarginTop: '5rem' }}>
|
<main id="main-content" className={styles.mainContent}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
@@ -150,7 +152,7 @@ export const DefaultLayout = (props: Props) => {
|
|||||||
{/* Need to set an explicit height for sticky elements since we also
|
{/* Need to set an explicit height for sticky elements since we also
|
||||||
set overflow to auto */}
|
set overflow to auto */}
|
||||||
<div className="flex-column flex-1 min-width-0">
|
<div className="flex-column flex-1 min-width-0">
|
||||||
<main id="main-content" style={{ scrollMarginTop: '5rem' }}>
|
<main id="main-content" className={styles.mainContent}>
|
||||||
<DeprecationBanner />
|
<DeprecationBanner />
|
||||||
<RestBanner />
|
<RestBanner />
|
||||||
|
|
||||||
|
|||||||
3
src/frame/components/GenericError.module.scss
Normal file
3
src/frame/components/GenericError.module.scss
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.logoContainer {
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@ import { useRouter } from 'next/router'
|
|||||||
import { MarkGithubIcon, CommentDiscussionIcon } from '@primer/octicons-react'
|
import { MarkGithubIcon, CommentDiscussionIcon } from '@primer/octicons-react'
|
||||||
import { Lead } from '@/frame/components/ui/Lead'
|
import { Lead } from '@/frame/components/ui/Lead'
|
||||||
|
|
||||||
|
import styles from './GenericError.module.scss'
|
||||||
|
|
||||||
export function GenericError() {
|
export function GenericError() {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen d-flex flex-column">
|
<div className="min-h-screen d-flex flex-column">
|
||||||
@@ -44,7 +46,7 @@ export const SimpleHeader = () => {
|
|||||||
role="banner"
|
role="banner"
|
||||||
aria-label="Main"
|
aria-label="Main"
|
||||||
>
|
>
|
||||||
<div className="d-flex flex-items-center" style={{ zIndex: 3 }} id="github-logo-mobile">
|
<div className={`d-flex flex-items-center ${styles.logoContainer}`} id="github-logo-mobile">
|
||||||
<Link href={`/${router.locale}`} aria-hidden="true" tabIndex={-1}>
|
<Link href={`/${router.locale}`} aria-hidden="true" tabIndex={-1}>
|
||||||
<MarkGithubIcon size={32} className="color-fg-default" />
|
<MarkGithubIcon size={32} className="color-fg-default" />
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -57,3 +57,7 @@
|
|||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.headerContainer {
|
||||||
|
row-gap: 1rem;
|
||||||
|
}
|
||||||
|
|||||||
@@ -156,11 +156,10 @@ export const Header = () => {
|
|||||||
aria-label="Main"
|
aria-label="Main"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="d-flex flex-justify-between p-2 flex-items-center flex-wrap"
|
className={cx(
|
||||||
style={{
|
'd-flex flex-justify-between p-2 flex-items-center flex-wrap',
|
||||||
// In the rare case of header overflow, create a pleasant gap between the rows
|
styles.headerContainer,
|
||||||
rowGap: '1rem',
|
)}
|
||||||
}}
|
|
||||||
data-testid="desktop-header"
|
data-testid="desktop-header"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -10,3 +10,29 @@
|
|||||||
visibility: hidden !important;
|
visibility: hidden !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The ... menu button when the smaller width search UI is open. Since the search
|
||||||
|
// UI is open, we don't show the button at smaller widths but we do show it as
|
||||||
|
// the browser width increases to md, and then at lg and above widths we hide
|
||||||
|
// the button again since the pickers and sign-up button are shown in the header.
|
||||||
|
.menuButtonSearchOpen {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
@include breakpoint(md) {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ... menu button when the smaller width search UI is closed, the button is
|
||||||
|
// shown up to lg. At lg and above we don't show the button since the pickers
|
||||||
|
// and sign-up button are shown in the header.
|
||||||
|
.menuButtonSearchClosed {
|
||||||
|
margin-left: 1rem;
|
||||||
|
|
||||||
|
@include breakpoint(lg) {
|
||||||
|
margin-left: 0;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -55,36 +55,8 @@ export function HeaderSearchAndWidgets({ width, isSearchOpen, SearchButton }: Pr
|
|||||||
data-testid="mobile-menu"
|
data-testid="mobile-menu"
|
||||||
icon={KebabHorizontalIcon}
|
icon={KebabHorizontalIcon}
|
||||||
aria-label={t('header.open_menu_label')}
|
aria-label={t('header.open_menu_label')}
|
||||||
sx={
|
className={
|
||||||
isSearchOpen
|
isSearchOpen ? styles.menuButtonSearchOpen : styles.menuButtonSearchClosed
|
||||||
? // The ... menu button when the smaller width search UI is open. Since the search
|
|
||||||
// UI is open, we don't show the button at smaller widths but we do show it as
|
|
||||||
// the browser width increases to md, and then at lg and above widths we hide
|
|
||||||
// the button again since the pickers and sign-up button are shown in the header.
|
|
||||||
{
|
|
||||||
marginLeft: '8px',
|
|
||||||
display: 'none',
|
|
||||||
// breakpoint(md)
|
|
||||||
'@media (min-width: 768px)': {
|
|
||||||
display: 'inline-block',
|
|
||||||
marginLeft: '4px',
|
|
||||||
},
|
|
||||||
// breakpoint(lg)
|
|
||||||
'@media (min-width: 1012px)': {
|
|
||||||
display: 'inline-block',
|
|
||||||
marginLeft: '4px',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: // The ... menu button when the smaller width search UI is closed, the button is
|
|
||||||
// shown up to md. At lg and above we don't show the button since the pickers
|
|
||||||
// and sign-up button are shown in the header.
|
|
||||||
{
|
|
||||||
marginLeft: '16px',
|
|
||||||
'@media (min-width: 1012px)': {
|
|
||||||
marginLeft: '0',
|
|
||||||
display: 'none',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</ActionMenu.Anchor>
|
</ActionMenu.Anchor>
|
||||||
|
|||||||
33
src/frame/components/sidebar/SidebarNav.module.scss
Normal file
33
src/frame/components/sidebar/SidebarNav.module.scss
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
.sidebarFull {
|
||||||
|
// Fixed width for consistent sidebar layout
|
||||||
|
width: 326px;
|
||||||
|
// 65px accounts for the header height
|
||||||
|
height: calc(100vh - 65px);
|
||||||
|
top: 65px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebarContentFull {
|
||||||
|
width: 326px;
|
||||||
|
// 175px accounts for header (65px) + sidebar header (110px)
|
||||||
|
height: calc(100vh - 175px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebarContentOverlay {
|
||||||
|
// Padding to account for header + sidebar header so content isn't cut off
|
||||||
|
padding-bottom: 185px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebarContentOverlayRest {
|
||||||
|
// Extra padding for REST pages (includes API version picker)
|
||||||
|
padding-bottom: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebarContentFullWithPadding {
|
||||||
|
// Padding to account for header + sidebar header so content isn't cut off
|
||||||
|
padding-bottom: 185px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebarContentFullWithPaddingRest {
|
||||||
|
// Extra padding for REST pages (includes API version picker)
|
||||||
|
padding-bottom: 250px;
|
||||||
|
}
|
||||||
@@ -8,6 +8,8 @@ import { AllProductsLink } from './AllProductsLink'
|
|||||||
import { ApiVersionPicker } from '@/rest/components/ApiVersionPicker'
|
import { ApiVersionPicker } from '@/rest/components/ApiVersionPicker'
|
||||||
import { Link } from '@/frame/components/Link'
|
import { Link } from '@/frame/components/Link'
|
||||||
|
|
||||||
|
import styles from './SidebarNav.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
variant?: 'full' | 'overlay'
|
variant?: 'full' | 'overlay'
|
||||||
}
|
}
|
||||||
@@ -22,20 +24,15 @@ export const SidebarNav = ({ variant = 'full' }: Props) => {
|
|||||||
// Early access does not have a "home page" unless it's local dev
|
// Early access does not have a "home page" unless it's local dev
|
||||||
(process.env.NODE_ENV === 'development' || currentProduct.id !== 'early-access')
|
(process.env.NODE_ENV === 'development' || currentProduct.id !== 'early-access')
|
||||||
|
|
||||||
// we need to roughly account for the site header height plus the height of
|
|
||||||
// the side nav header (which is taller when we show the API version picker)
|
|
||||||
// so we don't cut off the bottom of the sidebar
|
|
||||||
const sidebarPaddingBottom = isRestPage ? '250px' : '185px'
|
|
||||||
|
|
||||||
const isSearch = currentProduct?.id === 'search'
|
const isSearch = currentProduct?.id === 'search'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-container="nav"
|
data-container="nav"
|
||||||
className={cx(variant === 'full' ? 'position-sticky d-none border-right d-xxl-block' : '')}
|
className={cx(
|
||||||
style={
|
variant === 'full' ? 'position-sticky d-none border-right d-xxl-block' : '',
|
||||||
variant === 'full' ? { width: 326, height: 'calc(100vh - 65px)', top: '65px' } : undefined
|
variant === 'full' && styles.sidebarFull,
|
||||||
}
|
)}
|
||||||
>
|
>
|
||||||
<nav
|
<nav
|
||||||
aria-labelledby="allproducts-menu"
|
aria-labelledby="allproducts-menu"
|
||||||
@@ -68,12 +65,16 @@ export const SidebarNav = ({ variant = 'full' }: Props) => {
|
|||||||
? 'width-full d-xxl-none'
|
? 'width-full d-xxl-none'
|
||||||
: 'border-right d-none d-xxl-block overflow-y-auto',
|
: 'border-right d-none d-xxl-block overflow-y-auto',
|
||||||
'bg-primary flex-shrink-0',
|
'bg-primary flex-shrink-0',
|
||||||
)}
|
|
||||||
style={
|
|
||||||
variant === 'overlay'
|
variant === 'overlay'
|
||||||
? { paddingBottom: sidebarPaddingBottom }
|
? isRestPage
|
||||||
: { width: 326, height: 'calc(100vh - 175px)', paddingBottom: sidebarPaddingBottom }
|
? styles.sidebarContentOverlayRest
|
||||||
}
|
: styles.sidebarContentOverlay
|
||||||
|
: styles.sidebarContentFull,
|
||||||
|
variant === 'full' &&
|
||||||
|
(isRestPage
|
||||||
|
? styles.sidebarContentFullWithPaddingRest
|
||||||
|
: styles.sidebarContentFullWithPadding),
|
||||||
|
)}
|
||||||
role="region"
|
role="region"
|
||||||
aria-label="Page navigation content"
|
aria-label="Page navigation content"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -32,3 +32,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.codeBlockContainer {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyButton {
|
||||||
|
position: absolute;
|
||||||
|
right: -0.7rem;
|
||||||
|
top: -0.7rem;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import useCopyClipboard from '@/rest/components/useClipboard'
|
|||||||
import { EventType } from '@/events/types'
|
import { EventType } from '@/events/types'
|
||||||
import { sendEvent } from '@/events/components/events'
|
import { sendEvent } from '@/events/components/events'
|
||||||
|
|
||||||
|
import styles from './MarkdownContent.module.scss'
|
||||||
|
|
||||||
export type MarkdownContentPropsT = {
|
export type MarkdownContentPropsT = {
|
||||||
children: string
|
children: string
|
||||||
className?: string
|
className?: string
|
||||||
@@ -72,11 +74,11 @@ export const UnrenderedMarkdownContent = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ position: 'relative' }}>
|
<div className={styles.codeBlockContainer}>
|
||||||
<IconButton
|
<IconButton
|
||||||
size="small"
|
size="small"
|
||||||
icon={isCopied ? CheckIcon : CopyIcon}
|
icon={isCopied ? CheckIcon : CopyIcon}
|
||||||
className="btn-octicon"
|
className={cx('btn-octicon', styles.copyButton)}
|
||||||
aria-label={getAriaLabel()}
|
aria-label={getAriaLabel()}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await copyToClipboard()
|
await copyToClipboard()
|
||||||
@@ -88,12 +90,6 @@ export const UnrenderedMarkdownContent = ({
|
|||||||
eventGroupId: eventGroupId,
|
eventGroupId: eventGroupId,
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
sx={{
|
|
||||||
position: 'absolute',
|
|
||||||
right: '-.7rem',
|
|
||||||
top: '-.7rem',
|
|
||||||
zIndex: 1,
|
|
||||||
}}
|
|
||||||
></IconButton>
|
></IconButton>
|
||||||
<code {...props}>{props.children}</code>
|
<code {...props}>{props.children}</code>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -59,13 +59,7 @@ export function MiniTocs({ miniTocItems }: MiniTocsPropsT) {
|
|||||||
<Heading
|
<Heading
|
||||||
as="h2"
|
as="h2"
|
||||||
id="in-this-article"
|
id="in-this-article"
|
||||||
className="mb-1 ml-3"
|
className={cx('mb-1 ml-3', styles.heading)}
|
||||||
sx={{
|
|
||||||
'@media (min-width: 1012px) and (max-width: 1400px)': {
|
|
||||||
marginTop: '2rem',
|
|
||||||
},
|
|
||||||
fontSize: 1,
|
|
||||||
}}
|
|
||||||
aria-label={t('miniToc')}
|
aria-label={t('miniToc')}
|
||||||
>
|
>
|
||||||
{t('miniToc')}
|
{t('miniToc')}
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
@import "@primer/css/support/variables/layout.scss";
|
||||||
|
@import "@primer/css/support/mixins/layout.scss";
|
||||||
|
@import "src/frame/stylesheets/breakpoint-xxl.scss";
|
||||||
|
|
||||||
.indentNested {
|
.indentNested {
|
||||||
padding-inline-start: 0;
|
padding-inline-start: 0;
|
||||||
}
|
}
|
||||||
@@ -18,3 +22,15 @@
|
|||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
font-size: var(--text-body-size-small);
|
||||||
|
|
||||||
|
@include breakpoint(lg) {
|
||||||
|
margin-top: 2rem;
|
||||||
|
|
||||||
|
@include breakpoint-xxl {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
.permissionsBox {
|
||||||
|
border-radius: 0.625rem;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: var(--borderColor-default);
|
||||||
|
padding: var(--base-size-16);
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import { Box } from '@primer/react'
|
|
||||||
import { PersonIcon, BriefcaseIcon } from '@primer/octicons-react'
|
import { PersonIcon, BriefcaseIcon } from '@primer/octicons-react'
|
||||||
|
|
||||||
import { useTranslation } from '@/languages/components/useTranslation'
|
import { useTranslation } from '@/languages/components/useTranslation'
|
||||||
|
|
||||||
|
import styles from './PermissionsStatement.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
product?: string
|
product?: string
|
||||||
permissions?: string
|
permissions?: string
|
||||||
@@ -12,7 +13,7 @@ export function PermissionsStatement({ product, permissions }: Props) {
|
|||||||
const { t } = useTranslation('pages')
|
const { t } = useTranslation('pages')
|
||||||
if (!permissions && !product) return null
|
if (!permissions && !product) return null
|
||||||
return (
|
return (
|
||||||
<Box sx={{ borderRadius: 10, borderStyle: 'solid', borderColor: 'border.default', p: 3 }}>
|
<div className={styles.permissionsBox}>
|
||||||
<div data-search="hide" data-testid="permissions-callout">
|
<div data-search="hide" data-testid="permissions-callout">
|
||||||
<div className="mb-3 d-inline-block">
|
<div className="mb-3 d-inline-block">
|
||||||
<h2 className="f4">{t('permissions_callout_title')}</h2>
|
<h2 className="f4">{t('permissions_callout_title')}</h2>
|
||||||
@@ -30,6 +31,6 @@ export function PermissionsStatement({ product, permissions }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Box>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,3 +16,8 @@
|
|||||||
outline-offset: -2px;
|
outline-offset: -2px;
|
||||||
box-shadow: 0 0 0 4px inset; // A little wider for the border radius :shrug:
|
box-shadow: 0 0 0 4px inset; // A little wider for the border radius :shrug:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scrollButton {
|
||||||
|
width: 2.5rem;
|
||||||
|
height: 2.5rem;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
import { ChevronUpIcon } from '@primer/octicons-react'
|
import { ChevronUpIcon } from '@primer/octicons-react'
|
||||||
|
|
||||||
import styles from './ScrollButton.module.scss'
|
import styles from './ScrollButton.module.scss'
|
||||||
|
|
||||||
const { transition200, opacity0, opacity100, customFocus } = styles
|
const { transition200, opacity0, opacity100, customFocus } = styles
|
||||||
@@ -70,8 +71,8 @@ export const ScrollButton = ({ className, ariaLabel }: ScrollButtonPropsT) => {
|
|||||||
'tooltipped tooltipped-n tooltipped-no-delay btn circle border-1',
|
'tooltipped tooltipped-n tooltipped-no-delay btn circle border-1',
|
||||||
'd-flex flex-items-center flex-justify-center',
|
'd-flex flex-items-center flex-justify-center',
|
||||||
customFocus,
|
customFocus,
|
||||||
|
styles.scrollButton,
|
||||||
)}
|
)}
|
||||||
style={{ width: 40, height: 40 }}
|
|
||||||
aria-label={ariaLabel}
|
aria-label={ariaLabel}
|
||||||
>
|
>
|
||||||
<ChevronUpIcon />
|
<ChevronUpIcon />
|
||||||
|
|||||||
3
src/graphql/pages/explorer.module.scss
Normal file
3
src/graphql/pages/explorer.module.scss
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.explorerIframe {
|
||||||
|
height: 45rem;
|
||||||
|
}
|
||||||
@@ -9,6 +9,8 @@ import {
|
|||||||
} from '@/automated-pipelines/components/AutomatedPageContext'
|
} from '@/automated-pipelines/components/AutomatedPageContext'
|
||||||
import { useEffect, useRef } from 'react'
|
import { useEffect, useRef } from 'react'
|
||||||
|
|
||||||
|
import styles from './explorer.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
mainContext: MainContextT
|
mainContext: MainContextT
|
||||||
graphqlExplorerUrl: string
|
graphqlExplorerUrl: string
|
||||||
@@ -34,8 +36,7 @@ export default function GQLExplorer({
|
|||||||
<div>
|
<div>
|
||||||
<iframe
|
<iframe
|
||||||
ref={graphiqlRef}
|
ref={graphiqlRef}
|
||||||
style={{ height: 715 }}
|
className={`border width-full ${styles.explorerIframe}`}
|
||||||
className="border width-full"
|
|
||||||
scrolling="no"
|
scrolling="no"
|
||||||
src={graphqlExplorerUrl}
|
src={graphqlExplorerUrl}
|
||||||
title="GitHub GraphQL API"
|
title="GitHub GraphQL API"
|
||||||
|
|||||||
12
src/languages/components/LanguagePicker.module.scss
Normal file
12
src/languages/components/LanguagePicker.module.scss
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.menuButton {
|
||||||
|
height: auto;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
span:first-child {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.languageLabel {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
@@ -6,6 +6,8 @@ import { useTranslation } from '@/languages/components/useTranslation'
|
|||||||
import { useUserLanguage } from '@/languages/components/useUserLanguage'
|
import { useUserLanguage } from '@/languages/components/useUserLanguage'
|
||||||
import { ActionList, ActionMenu, IconButton } from '@primer/react'
|
import { ActionList, ActionMenu, IconButton } from '@primer/react'
|
||||||
|
|
||||||
|
import styles from './LanguagePicker.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
xs?: boolean
|
xs?: boolean
|
||||||
mediumOrLower?: boolean
|
mediumOrLower?: boolean
|
||||||
@@ -79,15 +81,10 @@ export const LanguagePicker = ({ xs, mediumOrLower }: Props) => {
|
|||||||
<ActionMenu.Anchor>
|
<ActionMenu.Anchor>
|
||||||
<ActionMenu.Button
|
<ActionMenu.Button
|
||||||
variant="invisible"
|
variant="invisible"
|
||||||
className="color-fg-default width-full"
|
className={`color-fg-default width-full ${styles.menuButton}`}
|
||||||
aria-label={`Select language: current language is ${selectedLang.name}`}
|
aria-label={`Select language: current language is ${selectedLang.name}`}
|
||||||
sx={{
|
|
||||||
height: 'auto',
|
|
||||||
textAlign: 'left',
|
|
||||||
'span:first-child': { display: 'inline' },
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<span style={{ whiteSpace: 'pre-wrap' }}>{t('language_picker_label') + '\n'}</span>
|
<span className={styles.languageLabel}>{t('language_picker_label') + '\n'}</span>
|
||||||
<span className="color-fg-muted text-normal f6">{selectedLang.name}</span>
|
<span className="color-fg-muted text-normal f6">{selectedLang.name}</span>
|
||||||
</ActionMenu.Button>
|
</ActionMenu.Button>
|
||||||
</ActionMenu.Anchor>
|
</ActionMenu.Anchor>
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import { PatchNotes } from './PatchNotes'
|
|||||||
import { Link } from '@/frame/components/Link'
|
import { Link } from '@/frame/components/Link'
|
||||||
import { CurrentVersion, ReleaseNotePatch, GHESMessage } from './types'
|
import { CurrentVersion, ReleaseNotePatch, GHESMessage } from './types'
|
||||||
|
|
||||||
|
import styles from './PatchNotes.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
patch: ReleaseNotePatch
|
patch: ReleaseNotePatch
|
||||||
currentVersion: CurrentVersion
|
currentVersion: CurrentVersion
|
||||||
@@ -26,8 +28,7 @@ export function GHESReleaseNotePatch({
|
|||||||
return (
|
return (
|
||||||
<div ref={containerRef} className="mb-10 pb-6" id={patch.version}>
|
<div ref={containerRef} className="mb-10 pb-6" id={patch.version}>
|
||||||
<header
|
<header
|
||||||
style={{ zIndex: 1, marginTop: -1 }}
|
className={`container-md border-top border-bottom px-3 pt-4 pb-2 ${styles.patchHeader}`}
|
||||||
className="container-md border-top border-bottom px-3 pt-4 pb-2"
|
|
||||||
>
|
>
|
||||||
<div className="d-flex flex-justify-between flex-wrap">
|
<div className="d-flex flex-justify-between flex-wrap">
|
||||||
<h2 className="border-bottom-0 m-0 p-0 mt-2">
|
<h2 className="border-bottom-0 m-0 p-0 mt-2">
|
||||||
@@ -36,8 +37,7 @@ export function GHESReleaseNotePatch({
|
|||||||
|
|
||||||
{patch.release_candidate && (
|
{patch.release_candidate && (
|
||||||
<span
|
<span
|
||||||
className="IssueLabel color-bg-attention-emphasis color-fg-on-emphasis ml-3 flex-items-center d-inline-flex"
|
className={`IssueLabel color-bg-attention-emphasis color-fg-on-emphasis ml-3 flex-items-center d-inline-flex ${styles.releaseLabel}`}
|
||||||
style={{ whiteSpace: 'pre' }}
|
|
||||||
>
|
>
|
||||||
Release Candidate
|
Release Candidate
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -14,3 +14,12 @@
|
|||||||
top: 65px;
|
top: 65px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.patchHeader {
|
||||||
|
z-index: 1;
|
||||||
|
margin-top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.releaseLabel {
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
.responseCodeBlock {
|
.responseCodeBlock {
|
||||||
min-height: 120px;
|
min-height: 120px;
|
||||||
|
max-height: 60vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.segmentedControl {
|
.segmentedControl {
|
||||||
|
|||||||
@@ -100,7 +100,6 @@ export function RestCodeSamples({ operation, slug, heading }: Props) {
|
|||||||
const [selectedLanguage, setSelectedLanguage] = useState(languageSelectOptions[0])
|
const [selectedLanguage, setSelectedLanguage] = useState(languageSelectOptions[0])
|
||||||
const [selectedExample, setSelectedExample] = useState(exampleSelectOptions[0])
|
const [selectedExample, setSelectedExample] = useState(exampleSelectOptions[0])
|
||||||
const [selectedResponse, setSelectedResponse] = useState(responseSelectOptions[0])
|
const [selectedResponse, setSelectedResponse] = useState(responseSelectOptions[0])
|
||||||
const [responseMaxHeight, setResponseMaxHeight] = useState(0)
|
|
||||||
|
|
||||||
const isSingleExample = languageExamples.length === 1
|
const isSingleExample = languageExamples.length === 1
|
||||||
const displayedExample: ExampleT = languageExamples[selectedExample.languageIndex]
|
const displayedExample: ExampleT = languageExamples[selectedExample.languageIndex]
|
||||||
@@ -118,19 +117,6 @@ export function RestCodeSamples({ operation, slug, heading }: Props) {
|
|||||||
Cookies.set('codeSampleLanguagePreferred', languageKey)
|
Cookies.set('codeSampleLanguagePreferred', languageKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleResponseResize = () => {
|
|
||||||
if (requestCodeExample.current) {
|
|
||||||
const requestCodeHeight = requestCodeExample.current.clientHeight || 0
|
|
||||||
const { innerHeight: height } = window
|
|
||||||
if (responseCodeExample) {
|
|
||||||
// 520 pixels roughly accounts for the space taken up by the
|
|
||||||
// nav bar, headers, language picker, method section, and response
|
|
||||||
// picker
|
|
||||||
setResponseMaxHeight(height - requestCodeHeight - 520)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change the language based on cookies
|
// Change the language based on cookies
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// If the user previously selected a language preference and the language
|
// If the user previously selected a language preference and the language
|
||||||
@@ -152,7 +138,6 @@ export function RestCodeSamples({ operation, slug, heading }: Props) {
|
|||||||
// (ClientSideHighlightJS) will have already handled highlighting
|
// (ClientSideHighlightJS) will have already handled highlighting
|
||||||
if (reqElem && !firstRender.current) {
|
if (reqElem && !firstRender.current) {
|
||||||
highlightElement(reqElem)
|
highlightElement(reqElem)
|
||||||
handleResponseResize()
|
|
||||||
}
|
}
|
||||||
}, [selectedLanguage])
|
}, [selectedLanguage])
|
||||||
|
|
||||||
@@ -196,15 +181,6 @@ export function RestCodeSamples({ operation, slug, heading }: Props) {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
// Handle the resizing of the response section when the window is resized
|
|
||||||
useEffect(() => {
|
|
||||||
handleResponseResize()
|
|
||||||
window.addEventListener('resize', handleResponseResize)
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('resize', handleResponseResize)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const [isCopied, setCopied] = useClipboard(displayedExample[selectedLanguage] as string, {
|
const [isCopied, setCopied] = useClipboard(displayedExample[selectedLanguage] as string, {
|
||||||
successDuration: 1400,
|
successDuration: 1400,
|
||||||
})
|
})
|
||||||
@@ -360,7 +336,6 @@ export function RestCodeSamples({ operation, slug, heading }: Props) {
|
|||||||
'border-top rounded-1 my-0',
|
'border-top rounded-1 my-0',
|
||||||
)}
|
)}
|
||||||
data-highlight={'json'}
|
data-highlight={'json'}
|
||||||
style={{ maxHeight: responseMaxHeight }}
|
|
||||||
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
|
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -5,3 +5,7 @@
|
|||||||
.codeBlock code:not(td *) {
|
.codeBlock code:not(td *) {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stickyCodeColumn {
|
||||||
|
top: 6.5em;
|
||||||
|
}
|
||||||
|
|||||||
@@ -102,8 +102,10 @@ export function RestOperation({ operation }: Props) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="col-md-12 col-lg-6 position-sticky flex-self-start"
|
className={cx(
|
||||||
style={{ top: '6.5em' }}
|
'col-md-12 col-lg-6 position-sticky flex-self-start',
|
||||||
|
styles.stickyCodeColumn,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{hasCodeSamples && (
|
{hasCodeSamples && (
|
||||||
<RestCodeSamples
|
<RestCodeSamples
|
||||||
|
|||||||
@@ -3,3 +3,10 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.linkItem {
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ActionList } from '@primer/react'
|
import { ActionList } from '@primer/react'
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
|
import cx from 'classnames'
|
||||||
|
|
||||||
import { PickerItem } from './Picker'
|
import { PickerItem } from './Picker'
|
||||||
|
|
||||||
@@ -34,13 +35,10 @@ export const Fields = (fieldProps: {
|
|||||||
// variant span box in front of it. To date there isn't a possibility to have
|
// variant span box in front of it. To date there isn't a possibility to have
|
||||||
// an ActionMenu in Primer that allow non-selection variant items with selection
|
// an ActionMenu in Primer that allow non-selection variant items with selection
|
||||||
// variant items
|
// variant items
|
||||||
className={(item.extra?.arrow || item.extra?.info) && styles.extrasDisplay}
|
className={cx(
|
||||||
sx={{
|
(item.extra?.arrow || item.extra?.info) && styles.extrasDisplay,
|
||||||
':hover': {
|
styles.linkItem,
|
||||||
textDecoration: 'none',
|
)}
|
||||||
textAlign: 'left',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
role={item.extra?.arrow || item.extra?.info ? 'menuitem' : 'menuitemradio'}
|
role={item.extra?.arrow || item.extra?.info ? 'menuitem' : 'menuitemradio'}
|
||||||
>
|
>
|
||||||
{renderItem ? renderItem(item) : item.text}
|
{renderItem ? renderItem(item) : item.text}
|
||||||
|
|||||||
12
src/tools/components/Picker.module.scss
Normal file
12
src/tools/components/Picker.module.scss
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.menuButton {
|
||||||
|
height: auto;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
span:first-child {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pickerLabel {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import { ActionMenu } from '@primer/react'
|
|||||||
import { AnchorAlignment } from '@primer/behaviors'
|
import { AnchorAlignment } from '@primer/behaviors'
|
||||||
|
|
||||||
import { Fields } from './Fields'
|
import { Fields } from './Fields'
|
||||||
|
import styles from './Picker.module.scss'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
items: PickerItem[]
|
items: PickerItem[]
|
||||||
@@ -47,14 +48,9 @@ export const Picker = ({
|
|||||||
<ActionMenu.Button
|
<ActionMenu.Button
|
||||||
aria-label={ariaLabel}
|
aria-label={ariaLabel}
|
||||||
variant={buttonBorder ? 'default' : 'invisible'}
|
variant={buttonBorder ? 'default' : 'invisible'}
|
||||||
className="color-fg-default width-full p-1 pl-2 pr-2"
|
className={`color-fg-default width-full p-1 pl-2 pr-2 ${styles.menuButton}`}
|
||||||
sx={{
|
|
||||||
height: 'auto',
|
|
||||||
textAlign: 'left',
|
|
||||||
'span:first-child': { display: 'inline' },
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{pickerLabel && <span style={{ whiteSpace: 'pre-wrap' }}>{`${pickerLabel}`}</span>}
|
{pickerLabel && <span className={styles.pickerLabel}>{`${pickerLabel}`}</span>}
|
||||||
<span
|
<span
|
||||||
className={`f${descriptionFontSize} color-fg-muted text-normal`}
|
className={`f${descriptionFontSize} color-fg-muted text-normal`}
|
||||||
data-testid={dataTestId}
|
data-testid={dataTestId}
|
||||||
|
|||||||
@@ -157,9 +157,7 @@ export function Webhook({ webhook }: Props) {
|
|||||||
<Flash className="mb-5" variant="danger">
|
<Flash className="mb-5" variant="danger">
|
||||||
<p>{t('action_type_switch_error')}</p>
|
<p>{t('action_type_switch_error')}</p>
|
||||||
<p>
|
<p>
|
||||||
<code className="f6" style={{ background: 'none' }}>
|
<code className={`f6 ${styles.errorCode}`}>{error.toString()}</code>
|
||||||
{error.toString()}
|
|
||||||
</code>
|
|
||||||
</p>
|
</p>
|
||||||
</Flash>
|
</Flash>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -12,3 +12,7 @@
|
|||||||
padding: 8px 8px 16px;
|
padding: 8px 8px 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.errorCode {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user