-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: make control tabs linkable (#1423)
Co-authored-by: Andreas Berliner <andreas.berliner@siemens.com>
- Loading branch information
1 parent
0d1233d
commit fbd0b25
Showing
13 changed files
with
485 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 13 additions & 11 deletions
24
packages/documentation/docs/controls/_avatar_styleguide.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,23 @@ | ||
Avatars are visual or textual representations of individual identities and they are most often used to represent users logged into a system. Identity providers or user management systems usually provide identity information, and the amount of information provided varies from system to system. The avatar component offers different options to handle this. | ||
## Guidelines | ||
|
||
Avatars are visual or textual representations of individual identities, most often used to represent users logged into a system. Identity providers or user management systems usually provide identity information, and the amount of information provided varies from system to system. The avatar component offers different options to handle this. | ||
|
||
## Options | ||
### Options | ||
|
||
![Avatar overview](https://www.figma.com/design/wEptRgAezDU1z80Cn3eZ0o/iX-Pattern-Illustrations?type=design&node-id=963-565&mode=design&t=M9CowfOcGyqnSycV-4) | ||
|
||
| Option | Description and usage | | ||
| -------------------------- | ------------------------------------------------------------------------------------------------------------ | | ||
| Default (1) | Without any set option the visual is just a predefined placeholder graphic, it can be used when identity information is unavailable or cannot be used for other reasons.| | ||
| Initials (2) | Shows a string of one or two characters, can be used when only textual information is available. Examples: a user’s initials (JD for John Doe), the first character from the username (J for johndoe)| | ||
| Image (3) | Shows an image, can be used when identity information includes an image| | ||
|
||
## Behavior | ||
| Option | Description and usage | | ||
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| Default (1) | Without any option set, the visual is just a predefined placeholder graphic. It can be used when identity information is unavailable or cannot be used for other reasons. | | ||
| Initials (2) | Shows a string of one or two characters. Can be used when only textual information is available. Examples: A user’s initials (JD for John Doe) or the first character from the username (J for johndoe) | | ||
| Image (3) | Shows an image. Can be used when identity information includes an image | | ||
|
||
### Behavior | ||
|
||
The avatar is a display-only component with no further interactions. Images provided are proportionally scaled to fill the content. A circle shape clips the image. All image formats that browser engines support can be used. | ||
|
||
## Dos and Don’ts | ||
### Dos and Don’ts | ||
|
||
![Avatar dos and Don‘ts](https://www.figma.com/design/wEptRgAezDU1z80Cn3eZ0o/iX-Pattern-Illustrations?type=design&node-id=975-13&mode=design&t=SxUA6AcHswBAiIzi-4) | ||
![Avatar dos and don‘ts](https://www.figma.com/design/wEptRgAezDU1z80Cn3eZ0o/iX-Pattern-Illustrations?type=design&node-id=975-13&mode=design&t=SxUA6AcHswBAiIzi-4) | ||
|
||
- Don't use more than 2 characters when using the "Initials" option |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
packages/documentation/src/components/LinkableDocsTabs/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2024 Siemens AG | ||
* | ||
* SPDX-License-Identifier: MIT | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
import Tabs from '@theme/Tabs'; | ||
import TabItem from '@theme/TabItem'; | ||
import { iconCode, iconNavigation } from '@siemens/ix-icons/icons'; | ||
|
||
export const docsTabQueryString = 'current-tab'; | ||
export const guidelinesTabValue = 'guidelines'; | ||
export const developmentTabValue = 'development'; | ||
|
||
export default function LinkableDocsTabs(props: { children: [any, any] }) { | ||
return ( | ||
<Tabs queryString={docsTabQueryString}> | ||
<TabItem | ||
value={guidelinesTabValue} | ||
label="Guidelines" | ||
attributes={{ | ||
icon: iconNavigation, | ||
}} | ||
> | ||
{props.children[0]} | ||
</TabItem> | ||
|
||
<TabItem | ||
value={developmentTabValue} | ||
label="Development" | ||
attributes={{ | ||
icon: iconCode, | ||
}} | ||
> | ||
{props.children[1]} | ||
</TabItem> | ||
</Tabs> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React, { useLayoutEffect } from 'react'; | ||
import DocsRoot from '@theme-original/DocsRoot'; | ||
import type DocsRootType from '@theme/DocsRoot'; | ||
import type { WrapperProps } from '@docusaurus/types'; | ||
|
||
type Props = WrapperProps<typeof DocsRootType>; | ||
|
||
export default function DocsRootWrapper(props: Props): JSX.Element { | ||
const { history, location } = props; | ||
|
||
useLayoutEffect(() => { | ||
setTimeout(() => { | ||
history.push({ | ||
search: location.search, | ||
hash: location.hash, | ||
}); | ||
}); | ||
}, [location.search, location.hash]); | ||
|
||
return ( | ||
<> | ||
<DocsRoot {...props} /> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import React from 'react'; | ||
import clsx from 'clsx'; | ||
import { translate } from '@docusaurus/Translate'; | ||
import { useThemeConfig } from '@docusaurus/theme-common'; | ||
import Link from '@docusaurus/Link'; | ||
import useBrokenLinks from '@docusaurus/useBrokenLinks'; | ||
import type { Props } from '@theme/Heading'; | ||
|
||
import styles from './styles.module.css'; | ||
import { useLocation } from '@docusaurus/router'; | ||
import { docsTabQueryString } from '@site/src/components/LinkableDocsTabs'; | ||
|
||
export default function Heading({ as: As, id, ...props }: Props): JSX.Element { | ||
const location = useLocation(); | ||
const brokenLinks = useBrokenLinks(); | ||
const { | ||
navbar: { hideOnScroll }, | ||
} = useThemeConfig(); | ||
|
||
const searchParams = new URLSearchParams(location.search); | ||
const currentTab = searchParams.get(docsTabQueryString); | ||
|
||
// H1 headings do not need an id because they don't appear in the TOC. | ||
if (As === 'h1' || !id) { | ||
return <As {...props} id={undefined} />; | ||
} | ||
|
||
brokenLinks.collectAnchor(id); | ||
|
||
const anchorTitle = translate( | ||
{ | ||
id: 'theme.common.headingLinkTitle', | ||
message: 'Direct link to {heading}', | ||
description: 'Title for link to heading', | ||
}, | ||
{ | ||
heading: typeof props.children === 'string' ? props.children : id, | ||
} | ||
); | ||
|
||
let link = `#${id}`; | ||
|
||
if (currentTab === 'development' || currentTab === 'guidelines') { | ||
link = `?${docsTabQueryString}=${currentTab}${link}`; | ||
} | ||
|
||
return ( | ||
<As | ||
{...props} | ||
className={clsx( | ||
'anchor', | ||
hideOnScroll | ||
? styles.anchorWithHideOnScrollNavbar | ||
: styles.anchorWithStickyNavbar, | ||
props.className | ||
)} | ||
id={id} | ||
> | ||
{props.children} | ||
<Link | ||
className="hash-link" | ||
to={link} | ||
aria-label={anchorTitle} | ||
title={anchorTitle} | ||
> | ||
​ | ||
</Link> | ||
</As> | ||
); | ||
} |
28 changes: 28 additions & 0 deletions
28
packages/documentation/src/theme/Heading/styles.module.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
When the navbar is sticky, ensure that on anchor click, | ||
the browser does not scroll that anchor behind the navbar | ||
See https://twitter.com/JoshWComeau/status/1332015868725891076 | ||
*/ | ||
.anchorWithStickyNavbar { | ||
scroll-margin-top: calc(var(--ifm-navbar-height) + 0.5rem); | ||
} | ||
|
||
.anchorWithHideOnScrollNavbar { | ||
scroll-margin-top: 0.5rem; | ||
} | ||
|
||
:global(.hash-link) { | ||
opacity: 0; | ||
padding-left: 0.5rem; | ||
transition: opacity var(--ifm-transition-fast); | ||
user-select: none; | ||
} | ||
|
||
:global(.hash-link::before) { | ||
content: '#'; | ||
} | ||
|
||
:global(.hash-link:focus), | ||
:global(*:hover > .hash-link) { | ||
opacity: 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import React, { useMemo } from 'react'; | ||
import Link from '@docusaurus/Link'; | ||
import type { Props } from '@theme/TOCItems/Tree'; | ||
import type { TOCTreeNode } from '@docusaurus/theme-common/internal'; | ||
import { useLocation } from '@docusaurus/router'; | ||
import { | ||
developmentTabValue, | ||
docsTabQueryString, | ||
guidelinesTabValue, | ||
} from '@site/src/components/LinkableDocsTabs'; | ||
|
||
type IxProps = Props & { | ||
parentTocItems: readonly TOCTreeNode[]; | ||
}; | ||
|
||
// Recursive component rendering the toc tree | ||
function TOCItemTree({ | ||
toc, | ||
className, | ||
linkClassName, | ||
isChild, | ||
parentTocItems, | ||
}: IxProps): JSX.Element | null { | ||
const _location = useLocation(); | ||
if (!toc.length) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<ul className={isChild ? undefined : className}> | ||
{toc.map((heading) => { | ||
const searchParams = new URLSearchParams(_location.search); | ||
|
||
let tabId = ''; | ||
parentTocItems?.forEach((tab) => { | ||
tab.children.forEach((child) => { | ||
if (child.id === heading.id) { | ||
searchParams.set(docsTabQueryString, tab.id); | ||
tabId = tab.id; | ||
} | ||
}); | ||
}); | ||
|
||
if (tabId === '' && !parentTocItems) { | ||
const tab = toc.find( | ||
(firstLevelHeading) => firstLevelHeading.id === heading.id | ||
); | ||
tabId = tab?.id ?? ''; | ||
} | ||
|
||
let queryParam = ''; | ||
if (tabId === guidelinesTabValue || tabId === developmentTabValue) { | ||
queryParam = `?${docsTabQueryString}=${tabId}`; | ||
} | ||
|
||
return ( | ||
<li key={heading.id}> | ||
<Link | ||
to={`${queryParam}#${heading.id}`} | ||
className={linkClassName ?? undefined} | ||
// Developer provided the HTML, so assume it's safe. | ||
dangerouslySetInnerHTML={{ __html: heading.value }} | ||
/> | ||
<TOCItemTree | ||
isChild | ||
toc={heading.children} | ||
parentTocItems={isChild ? parentTocItems : toc} | ||
className={className} | ||
linkClassName={linkClassName} | ||
/> | ||
</li> | ||
); | ||
})} | ||
</ul> | ||
); | ||
} | ||
|
||
// Memo only the tree root is enough | ||
export default React.memo(TOCItemTree); |
Oops, something went wrong.