Skip to content

Commit 28b8b92

Browse files
committed
feat: add reusable component for consistent documentation links
1 parent 57d625d commit 28b8b92

File tree

5 files changed

+109
-11
lines changed

5 files changed

+109
-11
lines changed

src/components/ExplorePage.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ export const ExplorePage = ({
4545
}
4646

4747
return (
48-
<div className='nt4-l'>
48+
// <div className='nt4-l'>
49+
<div>
4950
<Helmet>
5051
<title>{t('ExplorePage.title')}</title>
5152
</Helmet>

src/components/cid-info/CidInfo.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { useEffect, useState } from 'react'
22
import { useTranslation } from 'react-i18next'
33
import extractInfo, { type ExtractedInfo } from '../../lib/extract-info.js'
4+
import { DocLink } from '../common/DocLink'
45

56
export interface CidInfoProps extends React.HTMLAttributes<HTMLDivElement> {
67
cid: string | null
@@ -31,9 +32,9 @@ export const CidInfo: React.FC<CidInfoProps> = ({ cid, className, ...props }) =>
3132
return (
3233
<section className={`ph3 pv4 sans-serif ${className}`} {...props}>
3334
<label className='db pb2'>
34-
<a className='tracked ttu f5 fw2 teal-muted hover-aqua link' href='https://docs.ipfs.io/concepts/glossary/#cid' rel='external' target='_external'>
35+
<DocLink term='cid' className='tracked ttu f5 fw2'>
3536
{t('CidInfo.header')}
36-
</a>
37+
</DocLink>
3738
</label>
3839
{(cidInfo == null)
3940
? null
@@ -48,12 +49,9 @@ export const CidInfo: React.FC<CidInfoProps> = ({ cid, className, ...props }) =>
4849
<label htmlFor='CidInfo-human-readable-cid' className='db fw2 ma0 mid-gray ttu f7 tracked'>
4950
{t('base')} - {t('version')} - {t('codec')} - {t('multihash')}
5051
</label>
51-
<a
52-
href='https://docs.ipfs.io/concepts/glossary/#multihash' rel='external' target='_external'
53-
className='dib tracked ttu f6 fw2 teal-muted hover-aqua link mt4'
54-
>
52+
<DocLink term='multihash' className='dib tracked ttu f6 fw2 mt4'>
5553
{t('multihash')}
56-
</a>
54+
</DocLink>
5755
<div>
5856
<div className='dib monospace f6 pt2 tr dark-gray lh-title ph2'>
5957
<code className='gray'>0x</code>
@@ -68,10 +66,10 @@ export const CidInfo: React.FC<CidInfoProps> = ({ cid, className, ...props }) =>
6866
{t('CidInfo.hashDigest')}
6967
</label>
7068
<div className='tl lh-copy'>
71-
<a className='db orange no-underline pt2' href='https://docs.ipfs.io/concepts/glossary/#multicodec' rel='external' target='_external' title="Multicodec">
69+
<DocLink term='multicodec' className='db orange no-underline pt2' title='Multicodec'>
7270
<code className='gray'>0x</code>
7371
<code>{cidInfo.hashFnCode}</code> = {cidInfo.hashFn}
74-
</a>
72+
</DocLink>
7573
<div id='CidInfo-multihash' className='green'>
7674
<code className='gray'>0x</code>
7775
<code>{cidInfo.hashLengthCode}</code> = {cidInfo.hashLengthInBits} bits
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React from 'react'
2+
import { DocLink } from './DocLink'
3+
import type { Meta, StoryObj } from '@storybook/react'
4+
5+
const meta: Meta<typeof DocLink> = {
6+
title: 'Common/DocLink',
7+
component: DocLink,
8+
args: {
9+
term: 'cid',
10+
className: 'ma2'
11+
}
12+
}
13+
14+
export default meta
15+
type Story = StoryObj<typeof DocLink>
16+
17+
export const Default: Story = {
18+
args: {
19+
term: 'cid'
20+
}
21+
}
22+
23+
export const WithCustomText: Story = {
24+
args: {
25+
term: 'cid',
26+
children: 'Content Identifier'
27+
}
28+
}
29+
30+
export const WithCustomPath: Story = {
31+
args: {
32+
term: 'cid',
33+
glossaryPath: 'concepts/content-addressing'
34+
}
35+
}
36+
37+
export const MultipleLinks: Story = {
38+
render: () => (
39+
<div className='ma2'>
40+
<DocLink term='cid' className='mr2'>CID</DocLink>
41+
<DocLink term='multibase' className='mh2'>Multibase</DocLink>
42+
<DocLink term='multicodec' className='mh2'>Multicodec</DocLink>
43+
<DocLink term='multihash' className='ml2'>Multihash</DocLink>
44+
</div>
45+
)
46+
}

src/components/common/DocLink.tsx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import React from 'react'
2+
import { useTranslation } from 'react-i18next'
3+
4+
export interface DocLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
5+
term: string
6+
glossaryPath?: string
7+
children?: React.ReactNode
8+
}
9+
10+
/**
11+
* A component for rendering documentation links.
12+
* Links to the IPFS documentation glossary by default.
13+
*/
14+
export const DocLink: React.FC<DocLinkProps> = ({
15+
term,
16+
glossaryPath = 'concepts/glossary',
17+
children,
18+
className = '',
19+
...props
20+
}) => {
21+
const { t } = useTranslation('explore')
22+
const baseUrl = 'https://docs.ipfs.io'
23+
const href = `${baseUrl}/${glossaryPath}/#${term.toLowerCase()}`
24+
25+
return (
26+
<a
27+
href={href}
28+
rel='external'
29+
target='_external'
30+
title={t('docLinks.viewInDocs')}
31+
style={{ width: 'fit-content' }}
32+
className={`teal-muted hover-aqua link dib flex items-center ${className}`}
33+
{...props}
34+
>
35+
<span>{children ?? term}</span>
36+
<svg
37+
stroke="currentColor"
38+
fill="currentColor"
39+
strokeWidth="0"
40+
viewBox="0 0 512 512"
41+
height="14"
42+
width="14"
43+
className="ml1"
44+
xmlns="http://www.w3.org/2000/svg"
45+
>
46+
<path d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z"></path>
47+
</svg>
48+
</a>
49+
)
50+
}
51+
52+
export default DocLink

src/components/object-info/ObjectInfo.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next'
66
import { ObjectInspector, chromeLight } from 'react-inspector'
77
import getCodecNameFromCode from '../../lib/get-codec-name-from-code'
88
import { type NormalizedDagNode, type UnixFsNodeDataWithNumbers } from '../../types.js'
9+
import { DocLink } from '../common/DocLink.js'
910
import LargeLinksTable, { type LinkObject, type LargeLinksTableProps } from './links-table'
1011

1112
const humansize = partial({ round: 0 })
@@ -138,7 +139,7 @@ export const ObjectInfo: React.FC<ObjectInfoProps> = ({ className, type, cid, lo
138139
</span>
139140
{format === 'unixfs'
140141
? (
141-
<a className='dn di-ns no-underline charcoal ml2' href='https://docs.ipfs.io/concepts/glossary/#unixfs' rel='external' target='_external'>UnixFS</a>
142+
<DocLink style={{ color: '#34373f' }} term='unixfs' className='dn di-ns charcoal ml2'>UnixFS</DocLink>
142143
)
143144
: null}
144145
{isUnixFs

0 commit comments

Comments
 (0)