mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-19 17:55:17 -04:00
feat(frontend): replace forkawesome with bootstrap icons
These icon replace fork awesome. A linter informs the user about the deprecation. See https://github.com/hedgedoc/hedgedoc/issues/2929 Co-authored-by: Philip Molares <philip.molares@udo.edu> Co-authored-by: Tilman Vatteroth <git@tilmanvatteroth.de> Signed-off-by: Philip Molares <philip.molares@udo.edu> Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
e7246f1484
commit
1c16e25e14
179 changed files with 4974 additions and 1943 deletions
frontend/src/components/common
async-loading-boundary/__snapshots__
copyable
copy-to-clipboard-button
copyable-field
fork-awesome
__snapshots__
fork-awesome-icon.test.tsxfork-awesome-icon.tsxfork-awesome-icons.tsfork-awesome-stack.test.tsxfork-awesome-stack.tsxtypes.d.tshedge-doc-logo
icon-button
icons
links
__snapshots__
external-link.test.tsxexternal-link.tsxinternal-link.test.tsxinternal-link.tsxtypes.d.tslock-button
modals
note-loading-boundary
wait-spinner
|
@ -5,9 +5,7 @@ exports[`Async loading boundary shows a waiting spinner if loading 1`] = `
|
|||
<div
|
||||
class="m-3 d-flex align-items-center justify-content-center"
|
||||
>
|
||||
<i
|
||||
class="fa fa-spinner fa-spin "
|
||||
/>
|
||||
BootstrapIconMock_ArrowRepeat
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -7,9 +7,7 @@ exports[`Copy to clipboard button show an error text if clipboard api isn't avai
|
|||
title="renderer.highlightCode.copyCode"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
class="fa fa-files-o "
|
||||
/>
|
||||
BootstrapIconMock_Files
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
@ -22,9 +20,7 @@ exports[`Copy to clipboard button show an error text if clipboard api isn't avai
|
|||
title="renderer.highlightCode.copyCode"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
class="fa fa-files-o "
|
||||
/>
|
||||
BootstrapIconMock_Files
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
@ -36,9 +32,7 @@ exports[`Copy to clipboard button shows an error text if writing failed 1`] = `
|
|||
title="renderer.highlightCode.copyCode"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
class="fa fa-files-o "
|
||||
/>
|
||||
BootstrapIconMock_Files
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
@ -51,9 +45,7 @@ exports[`Copy to clipboard button shows an error text if writing failed 2`] = `
|
|||
title="renderer.highlightCode.copyCode"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
class="fa fa-files-o "
|
||||
/>
|
||||
BootstrapIconMock_Files
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
@ -65,9 +57,7 @@ exports[`Copy to clipboard button shows an success text if writing succeeded 1`]
|
|||
title="renderer.highlightCode.copyCode"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
class="fa fa-files-o "
|
||||
/>
|
||||
BootstrapIconMock_Files
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
@ -80,9 +70,7 @@ exports[`Copy to clipboard button shows an success text if writing succeeded 2`]
|
|||
title="renderer.highlightCode.copyCode"
|
||||
type="button"
|
||||
>
|
||||
<i
|
||||
class="fa fa-files-o "
|
||||
/>
|
||||
BootstrapIconMock_Files
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
*/
|
||||
import type { PropsWithDataCypressId } from '../../../../utils/cypress-attribute'
|
||||
import { cypressId } from '../../../../utils/cypress-attribute'
|
||||
import { ForkAwesomeIcon } from '../../fork-awesome/fork-awesome-icon'
|
||||
import { UiIcon } from '../../icons/ui-icon'
|
||||
import { useCopyOverlay } from '../hooks/use-copy-overlay'
|
||||
import React, { Fragment, useRef } from 'react'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import { Files as IconFiles } from 'react-bootstrap-icons'
|
||||
import type { Variant } from 'react-bootstrap/types'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
|
@ -46,7 +47,7 @@ export const CopyToClipboardButton: React.FC<CopyToClipboardButtonProps> = ({
|
|||
title={t('renderer.highlightCode.copyCode') ?? undefined}
|
||||
onClick={copyToClipboard}
|
||||
{...cypressId(props)}>
|
||||
<ForkAwesomeIcon icon='files-o' />
|
||||
<UiIcon icon={IconFiles} />
|
||||
</Button>
|
||||
{overlayElement}
|
||||
</Fragment>
|
||||
|
|
|
@ -5,11 +5,12 @@
|
|||
*/
|
||||
import { isClientSideRendering } from '../../../../utils/is-client-side-rendering'
|
||||
import { Logger } from '../../../../utils/logger'
|
||||
import { ForkAwesomeIcon } from '../../fork-awesome/fork-awesome-icon'
|
||||
import { UiIcon } from '../../icons/ui-icon'
|
||||
import { ShowIf } from '../../show-if/show-if'
|
||||
import { CopyToClipboardButton } from '../copy-to-clipboard-button/copy-to-clipboard-button'
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import { Button, FormControl, InputGroup } from 'react-bootstrap'
|
||||
import { Share as IconShare } from 'react-bootstrap-icons'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export interface CopyableFieldProps {
|
||||
|
@ -57,7 +58,7 @@ export const CopyableField: React.FC<CopyableFieldProps> = ({ content, shareOrig
|
|||
<ShowIf condition={sharingSupported}>
|
||||
<InputGroup.Text>
|
||||
<Button variant='secondary' title={'Share'} onClick={doShareAction}>
|
||||
<ForkAwesomeIcon icon='share-alt' />
|
||||
<UiIcon icon={IconShare} />
|
||||
</Button>
|
||||
</InputGroup.Text>
|
||||
</ShowIf>
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[` 1`] = `
|
||||
<div>
|
||||
<i
|
||||
class="fa fa-heart fa-stack-1x"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ForkAwesomeIcon renders a heart correctly 1`] = `
|
||||
<div>
|
||||
<i
|
||||
class="fa fa-heart "
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ForkAwesomeIcon renders in size 2x 1`] = `
|
||||
<div>
|
||||
<i
|
||||
class="fa fa-heart fa-2x"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ForkAwesomeIcon renders in size 3x 1`] = `
|
||||
<div>
|
||||
<i
|
||||
class="fa fa-heart fa-3x"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ForkAwesomeIcon renders in size 4x 1`] = `
|
||||
<div>
|
||||
<i
|
||||
class="fa fa-heart fa-4x"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ForkAwesomeIcon renders in size 5x 1`] = `
|
||||
<div>
|
||||
<i
|
||||
class="fa fa-heart fa-5x"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ForkAwesomeIcon renders with additional className 1`] = `
|
||||
<div>
|
||||
<i
|
||||
class="fa fa-heart testClass "
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ForkAwesomeIcon renders with fixed width icon 1`] = `
|
||||
<div>
|
||||
<i
|
||||
class="fa fa-fw fa-heart "
|
||||
/>
|
||||
</div>
|
||||
`;
|
|
@ -1,76 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ForkAwesomeStack renders a heart and a download icon stack 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="fa-stack "
|
||||
>
|
||||
<i
|
||||
class="fa fa-heart fa-stack-1x"
|
||||
/>
|
||||
<i
|
||||
class="fa fa-download fa-stack-1x"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ForkAwesomeStack renders in size 2x 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="fa-stack fa-2x"
|
||||
>
|
||||
<i
|
||||
class="fa fa-heart fa-stack-1x"
|
||||
/>
|
||||
<i
|
||||
class="fa fa-download fa-stack-1x"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ForkAwesomeStack renders in size 3x 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="fa-stack fa-3x"
|
||||
>
|
||||
<i
|
||||
class="fa fa-heart fa-stack-1x"
|
||||
/>
|
||||
<i
|
||||
class="fa fa-download fa-stack-1x"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ForkAwesomeStack renders in size 4x 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="fa-stack fa-4x"
|
||||
>
|
||||
<i
|
||||
class="fa fa-heart fa-stack-1x"
|
||||
/>
|
||||
<i
|
||||
class="fa fa-download fa-stack-1x"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ForkAwesomeStack renders in size 5x 1`] = `
|
||||
<div>
|
||||
<span
|
||||
class="fa-stack fa-5x"
|
||||
>
|
||||
<i
|
||||
class="fa fa-heart fa-stack-1x"
|
||||
/>
|
||||
<i
|
||||
class="fa fa-download fa-stack-1x"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { ForkAwesomeIcon } from './fork-awesome-icon'
|
||||
import type { IconName } from './types'
|
||||
import { render } from '@testing-library/react'
|
||||
|
||||
describe('ForkAwesomeIcon', () => {
|
||||
const icon: IconName = 'heart'
|
||||
it('renders a heart correctly', () => {
|
||||
const view = render(<ForkAwesomeIcon icon={icon} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('renders with fixed width icon', () => {
|
||||
const view = render(<ForkAwesomeIcon icon={icon} fixedWidth={true} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('renders with additional className', () => {
|
||||
const view = render(<ForkAwesomeIcon icon={icon} className={'testClass'} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
describe('renders in size', () => {
|
||||
it('2x', () => {
|
||||
const view = render(<ForkAwesomeIcon icon={icon} size={'2x'} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('3x', () => {
|
||||
const view = render(<ForkAwesomeIcon icon={icon} size={'3x'} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('4x', () => {
|
||||
const view = render(<ForkAwesomeIcon icon={icon} size={'4x'} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('5x', () => {
|
||||
const view = render(<ForkAwesomeIcon icon={icon} size={'5x'} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
describe('renders in stack', () => {
|
||||
const view = render(<ForkAwesomeIcon icon={icon} stacked={true} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
})
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import type { IconName, IconSize } from './types'
|
||||
import React from 'react'
|
||||
|
||||
export interface ForkAwesomeIconProps {
|
||||
icon: IconName
|
||||
className?: string
|
||||
fixedWidth?: boolean
|
||||
size?: IconSize
|
||||
stacked?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a fork awesome icon.
|
||||
*
|
||||
* @param icon The icon that should be rendered.
|
||||
* @param fixedWidth If the icon should be rendered with a fixed width.
|
||||
* @param size The size class the icon should be rendered in.
|
||||
* @param className Additional classes the icon should get.
|
||||
* @param stacked If the icon is part of a {@link ForkAwesomeStack stack}.
|
||||
* @see https://forkaweso.me
|
||||
*/
|
||||
export const ForkAwesomeIcon: React.FC<ForkAwesomeIconProps> = ({
|
||||
icon,
|
||||
fixedWidth = false,
|
||||
size,
|
||||
className,
|
||||
stacked = false
|
||||
}) => {
|
||||
const fixedWithClass = fixedWidth ? 'fa-fw' : ''
|
||||
const sizeClass = size ? `-${size}` : stacked ? '-1x' : ''
|
||||
const stackClass = stacked ? '-stack' : ''
|
||||
const extraClasses = `${className ?? ''} ${sizeClass || stackClass ? `fa${stackClass}${sizeClass}` : ''}`
|
||||
return <i className={`fa ${fixedWithClass} fa-${icon} ${extraClasses}`} />
|
||||
}
|
|
@ -1,804 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export const ForkAwesomeIcons = [
|
||||
'500px',
|
||||
'activitypub',
|
||||
'address-book-o',
|
||||
'address-book',
|
||||
'address-card-o',
|
||||
'address-card',
|
||||
'adjust',
|
||||
'adn',
|
||||
'align-center',
|
||||
'align-justify',
|
||||
'align-left',
|
||||
'align-right',
|
||||
'amazon',
|
||||
'ambulance',
|
||||
'american-sign-language-interpreting',
|
||||
'anchor',
|
||||
'android',
|
||||
'angellist',
|
||||
'angle-double-down',
|
||||
'angle-double-left',
|
||||
'angle-double-right',
|
||||
'angle-double-up',
|
||||
'angle-down',
|
||||
'angle-left',
|
||||
'angle-right',
|
||||
'angle-up',
|
||||
'apple',
|
||||
'archive-org',
|
||||
'archive',
|
||||
'archlinux',
|
||||
'area-chart',
|
||||
'arrow-circle-down',
|
||||
'arrow-circle-left',
|
||||
'arrow-circle-o-down',
|
||||
'arrow-circle-o-left',
|
||||
'arrow-circle-o-right',
|
||||
'arrow-circle-o-up',
|
||||
'arrow-circle-right',
|
||||
'arrow-circle-up',
|
||||
'arrow-down',
|
||||
'arrow-left',
|
||||
'arrow-right',
|
||||
'arrows-alt',
|
||||
'arrows-h',
|
||||
'arrows',
|
||||
'arrows-v',
|
||||
'arrow-up',
|
||||
'artstation',
|
||||
'askfm',
|
||||
'assistive-listening-systems',
|
||||
'asterisk',
|
||||
'at',
|
||||
'att',
|
||||
'audio-description',
|
||||
'backward',
|
||||
'balance-scale',
|
||||
'bandcamp',
|
||||
'ban',
|
||||
'bar-chart',
|
||||
'barcode',
|
||||
'bars',
|
||||
'bath',
|
||||
'battery-empty',
|
||||
'battery-full',
|
||||
'battery-half',
|
||||
'battery-quarter',
|
||||
'battery-three-quarters',
|
||||
'bed',
|
||||
'beer',
|
||||
'behance-square',
|
||||
'behance',
|
||||
'bell-o',
|
||||
'bell-rigning-o',
|
||||
'bell-ringing',
|
||||
'bell-slash-o',
|
||||
'bell-slash',
|
||||
'bell',
|
||||
'bicycle',
|
||||
'binoculars',
|
||||
'biometric',
|
||||
'birthday-cake',
|
||||
'bitbucket-square',
|
||||
'bitbucket',
|
||||
'black-tie',
|
||||
'blind',
|
||||
'blockstack',
|
||||
'bluetooth-b',
|
||||
'bluetooth',
|
||||
'boardgamegeek',
|
||||
'bold',
|
||||
'bolt',
|
||||
'bomb',
|
||||
'bookmark-o',
|
||||
'bookmark',
|
||||
'book',
|
||||
'bootstrap',
|
||||
'braille',
|
||||
'briefcase',
|
||||
'btc',
|
||||
'bug',
|
||||
'building-o',
|
||||
'building',
|
||||
'bullhorn',
|
||||
'bullseye',
|
||||
'bunny',
|
||||
'bus',
|
||||
'buymeacoffee',
|
||||
'buysellads',
|
||||
'calculator',
|
||||
'calendar-check-o',
|
||||
'calendar-minus-o',
|
||||
'calendar-o',
|
||||
'calendar-plus-o',
|
||||
'calendar',
|
||||
'calendar-times-o',
|
||||
'camera-retro',
|
||||
'camera',
|
||||
'caret-down',
|
||||
'caret-left',
|
||||
'caret-right',
|
||||
'caret-square-o-down',
|
||||
'caret-square-o-left',
|
||||
'caret-square-o-right',
|
||||
'caret-square-o-up',
|
||||
'caret-up',
|
||||
'car',
|
||||
'cart-arrow-down',
|
||||
'cart-plus',
|
||||
'cc-amex',
|
||||
'cc-by',
|
||||
'cc-cc',
|
||||
'cc-diners-club',
|
||||
'cc-discover',
|
||||
'cc-jcb',
|
||||
'cc-mastercard',
|
||||
'cc-nc-eu',
|
||||
'cc-nc-jp',
|
||||
'cc-nc',
|
||||
'cc-nd',
|
||||
'cc-paypal',
|
||||
'cc-pd',
|
||||
'cc-remix',
|
||||
'cc-sa',
|
||||
'cc-share',
|
||||
'cc-stripe',
|
||||
'cc',
|
||||
'cc-visa',
|
||||
'cc-zero',
|
||||
'certificate',
|
||||
'chain-broken',
|
||||
'check-circle-o',
|
||||
'check-circle',
|
||||
'check-square-o',
|
||||
'check-square',
|
||||
'check',
|
||||
'chevron-circle-down',
|
||||
'chevron-circle-left',
|
||||
'chevron-circle-right',
|
||||
'chevron-circle-up',
|
||||
'chevron-down',
|
||||
'chevron-left',
|
||||
'chevron-right',
|
||||
'chevron-up',
|
||||
'child',
|
||||
'chrome',
|
||||
'circle-o-notch',
|
||||
'circle-o',
|
||||
'circle',
|
||||
'circle-thin',
|
||||
'classicpress-circle',
|
||||
'classicpress',
|
||||
'clipboard',
|
||||
'clock-o',
|
||||
'clone',
|
||||
'cloud-download',
|
||||
'cloud',
|
||||
'cloud-upload',
|
||||
'code-fork',
|
||||
'codepen',
|
||||
'code',
|
||||
'codiepie',
|
||||
'coffee',
|
||||
'cogs',
|
||||
'cog',
|
||||
'columns',
|
||||
'commenting-o',
|
||||
'commenting',
|
||||
'comment-o',
|
||||
'comments-o',
|
||||
'comments',
|
||||
'comment',
|
||||
'compass',
|
||||
'compress',
|
||||
'connectdevelop',
|
||||
'contao',
|
||||
'conway-glider',
|
||||
'copyright',
|
||||
'creative-commons',
|
||||
'credit-card-alt',
|
||||
'credit-card',
|
||||
'crop',
|
||||
'crosshairs',
|
||||
'csharp',
|
||||
'css3',
|
||||
'c',
|
||||
'cubes',
|
||||
'cube',
|
||||
'cutlery',
|
||||
'dashcube',
|
||||
'database',
|
||||
'deaf',
|
||||
'debian',
|
||||
'delicious',
|
||||
'desktop',
|
||||
'deviantart',
|
||||
'dev-to',
|
||||
'diamond',
|
||||
'diaspora',
|
||||
'digg',
|
||||
'digitalocean',
|
||||
'discord-alt',
|
||||
'discord',
|
||||
'dogmazic',
|
||||
'dot-circle-o',
|
||||
'download',
|
||||
'dribbble',
|
||||
'dropbox',
|
||||
'drupal',
|
||||
'edge',
|
||||
'eercast',
|
||||
'eject',
|
||||
'ellipsis-h',
|
||||
'ellipsis-v',
|
||||
'email-bulk-o',
|
||||
'email-bulk',
|
||||
'emby',
|
||||
'empire',
|
||||
'envelope-open-o',
|
||||
'envelope-open',
|
||||
'envelope-o',
|
||||
'envelope-square',
|
||||
'envelope',
|
||||
'envira',
|
||||
'eraser',
|
||||
'ethereum',
|
||||
'etsy',
|
||||
'eur',
|
||||
'exchange',
|
||||
'exclamation-circle',
|
||||
'exclamation',
|
||||
'exclamation-triangle',
|
||||
'expand',
|
||||
'expeditedssl',
|
||||
'external-link-square',
|
||||
'external-link',
|
||||
'eyedropper',
|
||||
'eye-slash',
|
||||
'eye',
|
||||
'facebook-messenger',
|
||||
'facebook-official',
|
||||
'facebook-square',
|
||||
'facebook',
|
||||
'fast-backward',
|
||||
'fast-forward',
|
||||
'fax',
|
||||
'f-droid',
|
||||
'female',
|
||||
'ffmpeg',
|
||||
'fighter-jet',
|
||||
'file-archive-o',
|
||||
'file-audio-o',
|
||||
'file-code-o',
|
||||
'file-epub',
|
||||
'file-excel-o',
|
||||
'file-image-o',
|
||||
'file-o',
|
||||
'file-pdf-o',
|
||||
'file-powerpoint-o',
|
||||
'files-o',
|
||||
'file',
|
||||
'file-text-o',
|
||||
'file-text',
|
||||
'file-video-o',
|
||||
'file-word-o',
|
||||
'film',
|
||||
'filter',
|
||||
'fire-extinguisher',
|
||||
'firefox',
|
||||
'fire',
|
||||
'first-order',
|
||||
'flag-checkered',
|
||||
'flag-o',
|
||||
'flag',
|
||||
'flask',
|
||||
'flickr',
|
||||
'floppy-o',
|
||||
'folder-open-o',
|
||||
'folder-open',
|
||||
'folder-o',
|
||||
'folder',
|
||||
'font-awesome',
|
||||
'fonticons',
|
||||
'font',
|
||||
'fork-awesome',
|
||||
'fort-awesome',
|
||||
'forumbee',
|
||||
'forward',
|
||||
'foursquare',
|
||||
'free-code-camp',
|
||||
'freedombox',
|
||||
'friendica',
|
||||
'frown-o',
|
||||
'funkwhale',
|
||||
'futbol-o',
|
||||
'gamepad',
|
||||
'gavel',
|
||||
'gbp',
|
||||
'genderless',
|
||||
'get-pocket',
|
||||
'gg-circle',
|
||||
'gg',
|
||||
'gift',
|
||||
'gimp',
|
||||
'gitea',
|
||||
'github-alt',
|
||||
'github-square',
|
||||
'github',
|
||||
'gitlab',
|
||||
'git-square',
|
||||
'git',
|
||||
'glass',
|
||||
'glide-g',
|
||||
'glide',
|
||||
'globe-e',
|
||||
'globe',
|
||||
'globe-w',
|
||||
'gnupg',
|
||||
'gnu-social',
|
||||
'gnu',
|
||||
'google-play',
|
||||
'google-plus-official',
|
||||
'google-plus-square',
|
||||
'google-plus',
|
||||
'google',
|
||||
'google-wallet',
|
||||
'graduation-cap',
|
||||
'gratipay',
|
||||
'grav',
|
||||
'hackaday',
|
||||
'hacker-news',
|
||||
'hackster',
|
||||
'hal',
|
||||
'hand-lizard-o',
|
||||
'hand-o-down',
|
||||
'hand-o-left',
|
||||
'hand-o-right',
|
||||
'hand-o-up',
|
||||
'hand-paper-o',
|
||||
'hand-peace-o',
|
||||
'hand-pointer-o',
|
||||
'hand-rock-o',
|
||||
'hand-scissors-o',
|
||||
'handshake-o',
|
||||
'hand-spock-o',
|
||||
'hashnode',
|
||||
'hashtag',
|
||||
'hdd-o',
|
||||
'header',
|
||||
'headphones',
|
||||
'heartbeat',
|
||||
'heart-o',
|
||||
'heart',
|
||||
'heroku',
|
||||
'history',
|
||||
'home-assistant',
|
||||
'home',
|
||||
'hospital-o',
|
||||
'hourglass-end',
|
||||
'hourglass-half',
|
||||
'hourglass-o',
|
||||
'hourglass-start',
|
||||
'hourglass',
|
||||
'houzz',
|
||||
'h-square',
|
||||
'html5',
|
||||
'hubzilla',
|
||||
'i-cursor',
|
||||
'id-badge',
|
||||
'id-card-o',
|
||||
'id-card',
|
||||
'ils',
|
||||
'imdb',
|
||||
'inbox',
|
||||
'indent',
|
||||
'industry',
|
||||
'info-circle',
|
||||
'info',
|
||||
'inkscape',
|
||||
'inr',
|
||||
'instagram',
|
||||
'internet-explorer',
|
||||
'ioxhost',
|
||||
'italic',
|
||||
'java',
|
||||
'jirafeau',
|
||||
'joomla',
|
||||
'joplin',
|
||||
'jpy',
|
||||
'jsfiddle',
|
||||
'julia',
|
||||
'jupyter',
|
||||
'keybase',
|
||||
'keyboard-o',
|
||||
'key-modern',
|
||||
'key',
|
||||
'krw',
|
||||
'language',
|
||||
'laptop',
|
||||
'laravel',
|
||||
'lastfm-square',
|
||||
'lastfm',
|
||||
'leaf',
|
||||
'leanpub',
|
||||
'lemon-o',
|
||||
'level-down',
|
||||
'level-up',
|
||||
'liberapay-square',
|
||||
'liberapay',
|
||||
'life-ring',
|
||||
'lightbulb-o',
|
||||
'line-chart',
|
||||
'linkedin-square',
|
||||
'linkedin',
|
||||
'link',
|
||||
'linode',
|
||||
'linux',
|
||||
'list-alt',
|
||||
'list-ol',
|
||||
'list',
|
||||
'list-ul',
|
||||
'location-arrow',
|
||||
'lock',
|
||||
'long-arrow-down',
|
||||
'long-arrow-left',
|
||||
'long-arrow-right',
|
||||
'long-arrow-up',
|
||||
'low-vision',
|
||||
'magic',
|
||||
'magnet',
|
||||
'male',
|
||||
'map-marker',
|
||||
'map-o',
|
||||
'map-pin',
|
||||
'map-signs',
|
||||
'map',
|
||||
'mariadb',
|
||||
'markdown',
|
||||
'mars-double',
|
||||
'mars-stroke-h',
|
||||
'mars-stroke',
|
||||
'mars-stroke-v',
|
||||
'mars',
|
||||
'mastodon-alt',
|
||||
'mastodon-square',
|
||||
'mastodon',
|
||||
'matrix-org',
|
||||
'maxcdn',
|
||||
'meanpath',
|
||||
'medium-square',
|
||||
'medium',
|
||||
'medkit',
|
||||
'meetup',
|
||||
'meh-o',
|
||||
'mercury',
|
||||
'microchip',
|
||||
'microphone-slash',
|
||||
'microphone',
|
||||
'minus-circle',
|
||||
'minus-square-o',
|
||||
'minus-square',
|
||||
'minus',
|
||||
'mixcloud',
|
||||
'mobile',
|
||||
'modx',
|
||||
'money',
|
||||
'moon-o',
|
||||
'moon',
|
||||
'motorcycle',
|
||||
'mouse-pointer',
|
||||
'music',
|
||||
'mysql',
|
||||
'neuter',
|
||||
'newspaper-o',
|
||||
'nextcloud-square',
|
||||
'nextcloud',
|
||||
'nodejs',
|
||||
'nordcast',
|
||||
'object-group',
|
||||
'object-ungroup',
|
||||
'odnoklassniki-square',
|
||||
'odnoklassniki',
|
||||
'opencart',
|
||||
'open-collective',
|
||||
'openid',
|
||||
'opera',
|
||||
'optin-monster',
|
||||
'orcid',
|
||||
'outdent',
|
||||
'pagelines',
|
||||
'paint-brush',
|
||||
'paperclip',
|
||||
'paper-plane-o',
|
||||
'paper-plane',
|
||||
'paragraph',
|
||||
'patreon',
|
||||
'pause-circle-o',
|
||||
'pause-circle',
|
||||
'pause',
|
||||
'paw',
|
||||
'paypal',
|
||||
'peertube',
|
||||
'pencil-square-o',
|
||||
'pencil-square',
|
||||
'pencil',
|
||||
'percent',
|
||||
'phone-square',
|
||||
'phone',
|
||||
'php',
|
||||
'picture-o',
|
||||
'pie-chart',
|
||||
'pinterest-p',
|
||||
'pinterest-square',
|
||||
'pinterest',
|
||||
'pixelfed',
|
||||
'plane',
|
||||
'play-circle-o',
|
||||
'play-circle',
|
||||
'play',
|
||||
'pleroma',
|
||||
'plug',
|
||||
'plume',
|
||||
'plus-circle',
|
||||
'plus-square-o',
|
||||
'plus-square',
|
||||
'plus',
|
||||
'podcast',
|
||||
'postgresql',
|
||||
'power-off',
|
||||
'print',
|
||||
'product-hunt',
|
||||
'puzzle-piece',
|
||||
'python',
|
||||
'qq',
|
||||
'qrcode',
|
||||
'question-circle-o',
|
||||
'question-circle',
|
||||
'question',
|
||||
'quora',
|
||||
'quote-left',
|
||||
'quote-right',
|
||||
'random',
|
||||
'ravelry',
|
||||
'react',
|
||||
'rebel',
|
||||
'recycle',
|
||||
'reddit-alien',
|
||||
'reddit-square',
|
||||
'reddit',
|
||||
'refresh',
|
||||
'registered',
|
||||
'renren',
|
||||
'repeat',
|
||||
'reply-all',
|
||||
'reply',
|
||||
'researchgate',
|
||||
'retweet',
|
||||
'road',
|
||||
'rocket',
|
||||
'rss-square',
|
||||
'rss',
|
||||
'rub',
|
||||
'safari',
|
||||
'sass-alt',
|
||||
'sass',
|
||||
'scissors',
|
||||
'scribd',
|
||||
'scuttlebutt',
|
||||
'search-minus',
|
||||
'search-plus',
|
||||
'search',
|
||||
'sellsy',
|
||||
'server',
|
||||
'shaarli-o',
|
||||
'shaarli',
|
||||
'share-alt-square',
|
||||
'share-alt',
|
||||
'share-square-o',
|
||||
'share-square',
|
||||
'share',
|
||||
'shield',
|
||||
'ship',
|
||||
'shirtsinbulk',
|
||||
'shopping-bag',
|
||||
'shopping-basket',
|
||||
'shopping-cart',
|
||||
'shower',
|
||||
'signalapp',
|
||||
'signal',
|
||||
'sign-in',
|
||||
'sign-language',
|
||||
'sign-out',
|
||||
'simplybuilt',
|
||||
'sitemap',
|
||||
'skate',
|
||||
'sketchfab',
|
||||
'skyatlas',
|
||||
'skype',
|
||||
'slack',
|
||||
'sliders',
|
||||
'slideshare',
|
||||
'smile-o',
|
||||
'snapchat-ghost',
|
||||
'snapchat-square',
|
||||
'snapchat',
|
||||
'snowdrift',
|
||||
'snowflake-o',
|
||||
'social-home',
|
||||
'sort-alpha-asc',
|
||||
'sort-alpha-desc',
|
||||
'sort-amount-asc',
|
||||
'sort-amount-desc',
|
||||
'sort-asc',
|
||||
'sort-desc',
|
||||
'sort-numeric-asc',
|
||||
'sort-numeric-desc',
|
||||
'sort',
|
||||
'soundcloud',
|
||||
'space-shuttle',
|
||||
'spell-check',
|
||||
'spinner',
|
||||
'spoon',
|
||||
'spotify',
|
||||
'square-o',
|
||||
'square',
|
||||
'stack-exchange',
|
||||
'stack-overflow',
|
||||
'star-half-o',
|
||||
'star-half',
|
||||
'star-o',
|
||||
'star',
|
||||
'steam-square',
|
||||
'steam',
|
||||
'step-backward',
|
||||
'step-forward',
|
||||
'stethoscope',
|
||||
'sticky-note-o',
|
||||
'sticky-note',
|
||||
'stop-circle-o',
|
||||
'stop-circle',
|
||||
'stop',
|
||||
'street-view',
|
||||
'strikethrough',
|
||||
'stumbleupon-circle',
|
||||
'stumbleupon',
|
||||
'subscript',
|
||||
'subway',
|
||||
'suitcase',
|
||||
'sun-o',
|
||||
'sun',
|
||||
'superpowers',
|
||||
'superscript',
|
||||
'syncthing',
|
||||
'table',
|
||||
'tablet',
|
||||
'tachometer',
|
||||
'tags',
|
||||
'tag',
|
||||
'tasks',
|
||||
'taxi',
|
||||
'telegram',
|
||||
'television',
|
||||
'tencent-weibo',
|
||||
'terminal',
|
||||
'tex',
|
||||
'text-height',
|
||||
'textpattern',
|
||||
'text-width',
|
||||
'themeisle',
|
||||
'thermometer-empty',
|
||||
'thermometer-full',
|
||||
'thermometer-half',
|
||||
'thermometer-quarter',
|
||||
'thermometer-three-quarters',
|
||||
'th-large',
|
||||
'th-list',
|
||||
'th',
|
||||
'thumbs-down',
|
||||
'thumbs-o-down',
|
||||
'thumbs-o-up',
|
||||
'thumbs-up',
|
||||
'thumb-tack',
|
||||
'ticket',
|
||||
'times-circle-o',
|
||||
'times-circle',
|
||||
'times',
|
||||
'tint',
|
||||
'tipeee',
|
||||
'toggle-off',
|
||||
'toggle-on',
|
||||
'tor-onion',
|
||||
'trademark',
|
||||
'train',
|
||||
'transgender-alt',
|
||||
'transgender',
|
||||
'trash-o',
|
||||
'trash',
|
||||
'tree',
|
||||
'trello',
|
||||
'tripadvisor',
|
||||
'trophy',
|
||||
'truck',
|
||||
'try',
|
||||
'tty',
|
||||
'tumblr-square',
|
||||
'tumblr',
|
||||
'twitch',
|
||||
'twitter-square',
|
||||
'twitter',
|
||||
'umbrella',
|
||||
'underline',
|
||||
'undo',
|
||||
'unity',
|
||||
'universal-access',
|
||||
'university',
|
||||
'unlock-alt',
|
||||
'unlock',
|
||||
'unslpash',
|
||||
'upload',
|
||||
'usb',
|
||||
'usd',
|
||||
'user-circle-o',
|
||||
'user-circle',
|
||||
'user-md',
|
||||
'user-o',
|
||||
'user-plus',
|
||||
'user-secret',
|
||||
'users',
|
||||
'user',
|
||||
'user-times',
|
||||
'venus-double',
|
||||
'venus-mars',
|
||||
'venus',
|
||||
'viacoin',
|
||||
'viadeo-square',
|
||||
'viadeo',
|
||||
'video-camera',
|
||||
'vimeo-square',
|
||||
'vimeo',
|
||||
'vine',
|
||||
'vk',
|
||||
'volume-control-phone',
|
||||
'volume-down',
|
||||
'volume-mute',
|
||||
'volume-off',
|
||||
'volume-up',
|
||||
'weibo',
|
||||
'weixin',
|
||||
'whatsapp',
|
||||
'wheelchair-alt',
|
||||
'wheelchair',
|
||||
'wifi',
|
||||
'wikidata',
|
||||
'wikipedia-w',
|
||||
'window-close-o',
|
||||
'window-close',
|
||||
'window-maximize',
|
||||
'window-minimize',
|
||||
'window-restore',
|
||||
'windows',
|
||||
'wire',
|
||||
'wordpress',
|
||||
'wpbeginner',
|
||||
'wpexplorer',
|
||||
'wpforms',
|
||||
'wrench',
|
||||
'xing-square',
|
||||
'xing',
|
||||
'xmpp',
|
||||
'yahoo',
|
||||
'y-combinator',
|
||||
'yelp',
|
||||
'yoast',
|
||||
'youtube-play',
|
||||
'youtube-square',
|
||||
'youtube',
|
||||
'zotero'
|
||||
] as const
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import type { ForkAwesomeIconProps } from './fork-awesome-icon'
|
||||
import { ForkAwesomeIcon } from './fork-awesome-icon'
|
||||
import { ForkAwesomeStack } from './fork-awesome-stack'
|
||||
import { render } from '@testing-library/react'
|
||||
import type { ReactElement } from 'react'
|
||||
|
||||
describe('ForkAwesomeStack', () => {
|
||||
const stack: Array<ReactElement<ForkAwesomeIconProps>> = [
|
||||
<ForkAwesomeIcon icon={'heart'} key={'heart'} />,
|
||||
<ForkAwesomeIcon icon={'download'} key={'download'} />
|
||||
]
|
||||
it('renders a heart and a download icon stack', () => {
|
||||
const view = render(<ForkAwesomeStack>{stack}</ForkAwesomeStack>)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
describe('renders in size', () => {
|
||||
it('2x', () => {
|
||||
const view = render(<ForkAwesomeStack size={'2x'}>{stack}</ForkAwesomeStack>)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('3x', () => {
|
||||
const view = render(<ForkAwesomeStack size={'3x'}>{stack}</ForkAwesomeStack>)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('4x', () => {
|
||||
const view = render(<ForkAwesomeStack size={'4x'}>{stack}</ForkAwesomeStack>)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('5x', () => {
|
||||
const view = render(<ForkAwesomeStack size={'5x'}>{stack}</ForkAwesomeStack>)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import type { ForkAwesomeIconProps } from './fork-awesome-icon'
|
||||
import { ForkAwesomeIcon } from './fork-awesome-icon'
|
||||
import type { IconSize } from './types'
|
||||
import type { ReactElement } from 'react'
|
||||
import React from 'react'
|
||||
|
||||
export interface ForkAwesomeStackProps {
|
||||
size?: IconSize
|
||||
children: ReactElement<ForkAwesomeIconProps> | Array<ReactElement<ForkAwesomeIconProps>>
|
||||
}
|
||||
|
||||
/**
|
||||
* A stack of {@link ForkAwesomeIcon ForkAwesomeIcons}.
|
||||
*
|
||||
* @param size Which size the stack should have.
|
||||
* @param children One or more {@link ForkAwesomeIcon ForkAwesomeIcons} to be stacked.
|
||||
*/
|
||||
export const ForkAwesomeStack: React.FC<ForkAwesomeStackProps> = ({ size, children }) => {
|
||||
return (
|
||||
<span className={`fa-stack ${size ? 'fa-' : ''}${size ?? ''}`}>
|
||||
{React.Children.map(children, (child) => {
|
||||
if (!React.isValidElement<ForkAwesomeIconProps>(child)) {
|
||||
return null
|
||||
}
|
||||
return <ForkAwesomeIcon {...child.props} stacked={true} />
|
||||
})}
|
||||
</span>
|
||||
)
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import type { ForkAwesomeIcons } from './fork-awesome-icons'
|
||||
|
||||
export type IconName = (typeof ForkAwesomeIcons)[number]
|
||||
export type IconSize = '2x' | '3x' | '4x' | '5x'
|
|
@ -6,8 +6,7 @@
|
|||
import LogoBwHorizontal from './logo_text_bw_horizontal.svg'
|
||||
import LogoColorVertical from './logo_text_color_vertical.svg'
|
||||
import LogoWbHorizontal from './logo_text_wb_horizontal.svg'
|
||||
import React, { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import React from 'react'
|
||||
|
||||
export enum HedgeDocLogoSize {
|
||||
SMALL = 32,
|
||||
|
@ -33,17 +32,13 @@ export enum HedgeDocLogoType {
|
|||
* @param logoType The logo type to be used.
|
||||
*/
|
||||
export const HedgeDocLogoWithText: React.FC<HedgeDocLogoProps> = ({ size = HedgeDocLogoSize.MEDIUM, logoType }) => {
|
||||
const { t } = useTranslation()
|
||||
const altText = useMemo(() => t('app.icon'), [t])
|
||||
const style = useMemo(() => ({ height: size }), [size])
|
||||
|
||||
switch (logoType) {
|
||||
case HedgeDocLogoType.COLOR_VERTICAL:
|
||||
return <LogoColorVertical className={'w-auto'} title={altText} style={style} />
|
||||
return <LogoColorVertical className={'w-auto'} height={`${size}px`} width={'auto'} />
|
||||
case HedgeDocLogoType.BW_HORIZONTAL:
|
||||
return <LogoBwHorizontal className={'w-auto'} title={altText} style={style} />
|
||||
return <LogoBwHorizontal className={'w-auto'} height={`${size}px`} width={'auto'} />
|
||||
case HedgeDocLogoType.WB_HORIZONTAL:
|
||||
return <LogoWbHorizontal className={'w-auto'} title={altText} style={style} />
|
||||
return <LogoWbHorizontal className={'w-auto'} height={`${size}px`} width={'auto'} />
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -10,9 +10,7 @@ exports[`IconButton correctly uses the onClick callback 1`] = `
|
|||
<span
|
||||
class="icon-part d-flex align-items-center"
|
||||
>
|
||||
<i
|
||||
class="fa fa-heart icon "
|
||||
/>
|
||||
BootstrapIconMock_Heart
|
||||
</span>
|
||||
<span
|
||||
class="text-part d-flex align-items-center"
|
||||
|
@ -33,9 +31,7 @@ exports[`IconButton renders heart icon 1`] = `
|
|||
<span
|
||||
class="icon-part d-flex align-items-center"
|
||||
>
|
||||
<i
|
||||
class="fa fa-heart icon "
|
||||
/>
|
||||
BootstrapIconMock_Heart
|
||||
</span>
|
||||
<span
|
||||
class="text-part d-flex align-items-center"
|
||||
|
@ -56,9 +52,7 @@ exports[`IconButton renders with additional className 1`] = `
|
|||
<span
|
||||
class="icon-part d-flex align-items-center"
|
||||
>
|
||||
<i
|
||||
class="fa fa-heart icon "
|
||||
/>
|
||||
BootstrapIconMock_Heart
|
||||
</span>
|
||||
<span
|
||||
class="text-part d-flex align-items-center"
|
||||
|
@ -79,9 +73,7 @@ exports[`IconButton renders with border 1`] = `
|
|||
<span
|
||||
class="icon-part d-flex align-items-center"
|
||||
>
|
||||
<i
|
||||
class="fa fa-heart icon "
|
||||
/>
|
||||
BootstrapIconMock_Heart
|
||||
</span>
|
||||
<span
|
||||
class="text-part d-flex align-items-center"
|
||||
|
@ -91,26 +83,3 @@ exports[`IconButton renders with border 1`] = `
|
|||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`IconButton renders with fixed width icon 1`] = `
|
||||
<div>
|
||||
<button
|
||||
class="btn-icon p-0 d-inline-flex align-items-stretch btn btn-primary"
|
||||
data-testid="icon-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="icon-part d-flex align-items-center"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-heart icon "
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="text-part d-flex align-items-center"
|
||||
>
|
||||
test with fixed with icon
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -3,35 +3,26 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import type { IconName } from '../fork-awesome/types'
|
||||
import { IconButton } from './icon-button'
|
||||
import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import { Heart as IconHeart } from 'react-bootstrap-icons'
|
||||
|
||||
describe('IconButton', () => {
|
||||
const icon: IconName = 'heart'
|
||||
it('renders heart icon', () => {
|
||||
const view = render(<IconButton icon={icon}>test</IconButton>)
|
||||
const view = render(<IconButton icon={IconHeart}>test</IconButton>)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('renders with border', () => {
|
||||
const view = render(
|
||||
<IconButton icon={icon} border={true}>
|
||||
<IconButton icon={IconHeart} border={true}>
|
||||
test with border
|
||||
</IconButton>
|
||||
)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('renders with fixed width icon', () => {
|
||||
const view = render(
|
||||
<IconButton icon={icon} iconFixedWidth={true}>
|
||||
test with fixed with icon
|
||||
</IconButton>
|
||||
)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('renders with additional className', () => {
|
||||
const view = render(
|
||||
<IconButton icon={icon} className={'testClass'}>
|
||||
<IconButton icon={IconHeart} className={'testClass'}>
|
||||
test with additional className
|
||||
</IconButton>
|
||||
)
|
||||
|
@ -40,7 +31,7 @@ describe('IconButton', () => {
|
|||
it('correctly uses the onClick callback', async () => {
|
||||
const onClick = jest.fn()
|
||||
const view = render(
|
||||
<IconButton icon={icon} onClick={onClick}>
|
||||
<IconButton icon={IconHeart} onClick={onClick}>
|
||||
test with onClick
|
||||
</IconButton>
|
||||
)
|
||||
|
|
|
@ -5,37 +5,38 @@
|
|||
*/
|
||||
import type { PropsWithDataTestId } from '../../../utils/test-id'
|
||||
import { testId } from '../../../utils/test-id'
|
||||
import { ForkAwesomeIcon } from '../fork-awesome/fork-awesome-icon'
|
||||
import type { IconName } from '../fork-awesome/types'
|
||||
import { UiIcon } from '../icons/ui-icon'
|
||||
import { ShowIf } from '../show-if/show-if'
|
||||
import styles from './icon-button.module.scss'
|
||||
import React from 'react'
|
||||
import type { ButtonProps } from 'react-bootstrap'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import type { Icon } from 'react-bootstrap-icons'
|
||||
|
||||
export interface IconButtonProps extends ButtonProps, PropsWithDataTestId {
|
||||
icon: IconName
|
||||
icon: Icon
|
||||
onClick?: () => void
|
||||
border?: boolean
|
||||
iconFixedWidth?: boolean
|
||||
iconSize?: number | string
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic {@link Button button} with an {@link ForkAwesomeIcon icon} in it.
|
||||
* A generic {@link Button button} with an icon in it.
|
||||
*
|
||||
* @param icon Which icon should be used
|
||||
* @param children The children that will be added as the content of the button.
|
||||
* @param iconFixedWidth If the icon should be of fixed width.
|
||||
* @param border Should the button have a border.
|
||||
* @param className Additional class names added to the button.
|
||||
* @param iconSize Size of the icon
|
||||
* @param props Additional props for the button.
|
||||
*/
|
||||
export const IconButton: React.FC<IconButtonProps> = ({
|
||||
icon,
|
||||
children,
|
||||
iconFixedWidth = false,
|
||||
border = false,
|
||||
className,
|
||||
iconSize,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
|
@ -46,7 +47,7 @@ export const IconButton: React.FC<IconButtonProps> = ({
|
|||
}`}
|
||||
{...testId('icon-button')}>
|
||||
<span className={`${styles['icon-part']} d-flex align-items-center`}>
|
||||
<ForkAwesomeIcon icon={icon} fixedWidth={iconFixedWidth} className={'icon'} />
|
||||
<UiIcon size={iconSize} icon={icon} className={'icon'} />
|
||||
</span>
|
||||
<ShowIf condition={!!children}>
|
||||
<span className={`${styles['text-part']} d-flex align-items-center`}>{children}</span>
|
||||
|
|
1994
frontend/src/components/common/icons/bootstrap-icons.tsx
Normal file
1994
frontend/src/components/common/icons/bootstrap-icons.tsx
Normal file
File diff suppressed because it is too large
Load diff
38
frontend/src/components/common/icons/lazy-bootstrap-icon.tsx
Normal file
38
frontend/src/components/common/icons/lazy-bootstrap-icon.tsx
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { testId } from '../../../utils/test-id'
|
||||
import { BootstrapLazyIcons } from './bootstrap-icons'
|
||||
import type { BootstrapIconName } from './bootstrap-icons'
|
||||
import React, { Suspense, useMemo } from 'react'
|
||||
|
||||
export interface LazyBootstrapIconProps {
|
||||
icon: BootstrapIconName
|
||||
size?: number
|
||||
className?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a bootstrap icon.
|
||||
*
|
||||
* @param iconName the internal name of the icon
|
||||
* @param size the size of the icon - the default is 1
|
||||
* @see https://icons.getbootstrap.com/
|
||||
*/
|
||||
export const LazyBootstrapIcon: React.FC<LazyBootstrapIconProps> = ({ icon, size, className }) => {
|
||||
const fullSize = useMemo(() => `${size ?? 1}em`, [size])
|
||||
const Icon = BootstrapLazyIcons[icon]
|
||||
|
||||
return (
|
||||
<Suspense fallback={<></>}>
|
||||
<Icon
|
||||
width={fullSize}
|
||||
height={fullSize}
|
||||
fill={'currentColor'}
|
||||
className={className}
|
||||
{...testId(`lazy-bootstrap-icon-${icon}`)}></Icon>
|
||||
</Suspense>
|
||||
)
|
||||
}
|
47
frontend/src/components/common/icons/ui-icon.tsx
Normal file
47
frontend/src/components/common/icons/ui-icon.tsx
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import styles from './ui-icons.module.scss'
|
||||
import React, { Fragment, useMemo } from 'react'
|
||||
import type { Icon } from 'react-bootstrap-icons'
|
||||
|
||||
export interface UiIconProps {
|
||||
icon: Icon | undefined
|
||||
nbsp?: boolean
|
||||
size?: number | string
|
||||
className?: string
|
||||
spin?: boolean
|
||||
}
|
||||
|
||||
export const UiIcon: React.FC<UiIconProps> = ({ icon, nbsp, className, size, spin }) => {
|
||||
const finalSize = useMemo(() => {
|
||||
if (size === undefined) {
|
||||
return '1em'
|
||||
} else if (typeof size === 'number') {
|
||||
return `${size}em`
|
||||
} else {
|
||||
return size
|
||||
}
|
||||
}, [size])
|
||||
|
||||
const finalClassName = useMemo(() => {
|
||||
return `${spin ? styles.spin : ''} ${className ?? ''}`
|
||||
}, [className, spin])
|
||||
|
||||
if (icon) {
|
||||
return (
|
||||
<Fragment>
|
||||
{React.createElement(icon, {
|
||||
className: finalClassName,
|
||||
width: finalSize,
|
||||
height: finalSize
|
||||
})}
|
||||
{nbsp ? <Fragment> </Fragment> : null}
|
||||
</Fragment>
|
||||
)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
20
frontend/src/components/common/icons/ui-icons.module.scss
Normal file
20
frontend/src/components/common/icons/ui-icons.module.scss
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*!
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
.spin {
|
||||
transform-origin: center center;
|
||||
|
||||
@keyframes rotation {
|
||||
0% {
|
||||
transform: rotateZ(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotateZ(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
animation: rotation linear 2s infinite;
|
||||
}
|
|
@ -52,9 +52,7 @@ exports[`ExternalLink renders an external link with an icon 1`] = `
|
|||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-heart "
|
||||
/>
|
||||
BootstrapIconMock_Heart
|
||||
|
||||
testText
|
||||
</a>
|
||||
|
|
|
@ -40,9 +40,7 @@ exports[`InternalLink renders an internal link with an icon 1`] = `
|
|||
class="text-light"
|
||||
href="/test"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-heart "
|
||||
/>
|
||||
BootstrapIconMock_Heart
|
||||
|
||||
testText
|
||||
</a>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
import { ExternalLink } from './external-link'
|
||||
import { render } from '@testing-library/react'
|
||||
import { Heart as IconHeart } from 'react-bootstrap-icons'
|
||||
|
||||
describe('ExternalLink', () => {
|
||||
const href = 'https://example.com'
|
||||
|
@ -14,7 +15,7 @@ describe('ExternalLink', () => {
|
|||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('renders an external link with an icon', () => {
|
||||
const view = render(<ExternalLink text={text} href={href} icon={'heart'} />)
|
||||
const view = render(<ExternalLink text={text} href={href} icon={IconHeart} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('renders an external link with an id', () => {
|
||||
|
|
|
@ -3,9 +3,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { ForkAwesomeIcon } from '../fork-awesome/fork-awesome-icon'
|
||||
import type { IconName } from '../fork-awesome/types'
|
||||
import { ShowIf } from '../show-if/show-if'
|
||||
import { UiIcon } from '../icons/ui-icon'
|
||||
import type { LinkWithTextProps } from './types'
|
||||
import React from 'react'
|
||||
|
||||
|
@ -31,10 +29,7 @@ export const ExternalLink: React.FC<LinkWithTextProps> = ({
|
|||
}) => {
|
||||
return (
|
||||
<a href={href} target='_blank' rel='noopener noreferrer' id={id} className={className} title={title} dir='auto'>
|
||||
<ShowIf condition={!!icon}>
|
||||
<ForkAwesomeIcon icon={icon as IconName} fixedWidth={true} />
|
||||
|
||||
</ShowIf>
|
||||
<UiIcon icon={icon} nbsp={true} />
|
||||
{text}
|
||||
</a>
|
||||
)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
import { InternalLink } from './internal-link'
|
||||
import { render } from '@testing-library/react'
|
||||
import { Heart as IconHeart } from 'react-bootstrap-icons'
|
||||
|
||||
describe('InternalLink', () => {
|
||||
const href = '/test'
|
||||
|
@ -14,7 +15,7 @@ describe('InternalLink', () => {
|
|||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('renders an internal link with an icon', () => {
|
||||
const view = render(<InternalLink text={text} href={href} icon={'heart'} />)
|
||||
const view = render(<InternalLink text={text} href={href} icon={IconHeart} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
})
|
||||
it('renders an internal link with an id', () => {
|
||||
|
|
|
@ -3,9 +3,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { ForkAwesomeIcon } from '../fork-awesome/fork-awesome-icon'
|
||||
import type { IconName } from '../fork-awesome/types'
|
||||
import { ShowIf } from '../show-if/show-if'
|
||||
import { UiIcon } from '../icons/ui-icon'
|
||||
import type { LinkWithTextProps } from './types'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
|
@ -31,10 +29,7 @@ export const InternalLink: React.FC<LinkWithTextProps> = ({
|
|||
}) => {
|
||||
return (
|
||||
<Link href={href} className={className} id={id} title={title}>
|
||||
<ShowIf condition={!!icon}>
|
||||
<ForkAwesomeIcon icon={icon as IconName} fixedWidth={true} />
|
||||
|
||||
</ShowIf>
|
||||
<UiIcon icon={icon} nbsp={true} />
|
||||
{text}
|
||||
</Link>
|
||||
)
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import type { IconName } from '../fork-awesome/fork-awesome-icon'
|
||||
import type { TOptionsBase } from 'i18next'
|
||||
import type { Icon } from 'react-bootstrap-icons'
|
||||
|
||||
interface GeneralLinkProp {
|
||||
href: string
|
||||
icon?: IconName
|
||||
icon?: Icon
|
||||
id?: string
|
||||
className?: string
|
||||
title?: string
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { ForkAwesomeIcon } from '../fork-awesome/fork-awesome-icon'
|
||||
import React from 'react'
|
||||
import { Button } from 'react-bootstrap'
|
||||
|
||||
export interface LockButtonProps {
|
||||
locked: boolean
|
||||
onLockedChanged: (newState: boolean) => void
|
||||
title: string
|
||||
}
|
||||
|
||||
/**
|
||||
* A button with a lock icon.
|
||||
*
|
||||
* @param locked If the button should be shown as locked or not
|
||||
* @param onLockedChanged The callback to change the state from locked to unlocked and vise-versa.
|
||||
* @param title The title for the button.
|
||||
*/
|
||||
export const LockButton: React.FC<LockButtonProps> = ({ locked, onLockedChanged, title }) => {
|
||||
return (
|
||||
<Button variant='dark' size='sm' onClick={() => onLockedChanged(!locked)} title={title}>
|
||||
{locked ? <ForkAwesomeIcon icon='lock' /> : <ForkAwesomeIcon icon='unlock' />}
|
||||
</Button>
|
||||
)
|
||||
}
|
|
@ -148,9 +148,7 @@ exports[`CommonModal render correctly with title icon 1`] = `
|
|||
<div
|
||||
class="modal-title h4"
|
||||
>
|
||||
<i
|
||||
class="fa fa-heart "
|
||||
/>
|
||||
BootstrapIconMock_Heart
|
||||
|
||||
<span />
|
||||
</div>
|
||||
|
|
|
@ -7,6 +7,7 @@ import { mockI18n } from '../../markdown-renderer/test-utils/mock-i18n'
|
|||
import { CommonModal } from './common-modal'
|
||||
import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import React from 'react'
|
||||
import { Heart as IconHeart } from 'react-bootstrap-icons'
|
||||
|
||||
describe('CommonModal', () => {
|
||||
afterAll(() => {
|
||||
|
@ -65,7 +66,7 @@ describe('CommonModal', () => {
|
|||
|
||||
it('render correctly with title icon', async () => {
|
||||
render(
|
||||
<CommonModal show={true} titleIcon={'heart'}>
|
||||
<CommonModal show={true} titleIcon={IconHeart}>
|
||||
testText
|
||||
</CommonModal>
|
||||
)
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
import type { PropsWithDataCypressId } from '../../../utils/cypress-attribute'
|
||||
import { cypressId } from '../../../utils/cypress-attribute'
|
||||
import { testId } from '../../../utils/test-id'
|
||||
import { ForkAwesomeIcon } from '../fork-awesome/fork-awesome-icon'
|
||||
import type { IconName } from '../fork-awesome/types'
|
||||
import { UiIcon } from '../icons/ui-icon'
|
||||
import { ShowIf } from '../show-if/show-if'
|
||||
import type { PropsWithChildren } from 'react'
|
||||
import React, { useMemo } from 'react'
|
||||
import { Modal } from 'react-bootstrap'
|
||||
import type { Icon } from 'react-bootstrap-icons'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
|
||||
export interface ModalVisibilityProps {
|
||||
|
@ -23,7 +23,7 @@ export interface ModalContentProps {
|
|||
titleI18nKey?: string
|
||||
title?: string
|
||||
showCloseButton?: boolean
|
||||
titleIcon?: IconName
|
||||
titleIcon?: Icon
|
||||
modalSize?: 'lg' | 'sm' | 'xl'
|
||||
additionalClasses?: string
|
||||
}
|
||||
|
@ -74,10 +74,7 @@ export const CommonModal: React.FC<PropsWithChildren<CommonModalProps>> = ({
|
|||
size={modalSize}>
|
||||
<Modal.Header closeButton={!!showCloseButton}>
|
||||
<Modal.Title>
|
||||
<ShowIf condition={!!titleIcon}>
|
||||
<ForkAwesomeIcon icon={titleIcon as IconName} />
|
||||
|
||||
</ShowIf>
|
||||
<UiIcon icon={titleIcon} nbsp={true} />
|
||||
{titleElement}
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
|
|
|
@ -1,20 +1,5 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`create non existing note hint shows success message when the note has been created 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="fade mt-5 alert alert-info show"
|
||||
data-testid="noteCreated"
|
||||
role="alert"
|
||||
>
|
||||
<i
|
||||
class="fa fa-check-circle me-2 "
|
||||
/>
|
||||
noteLoadingBoundary.createNote.success
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`create non existing note hint renders a waiting message when button is clicked 1`] = `
|
||||
<div>
|
||||
<div
|
||||
|
@ -22,9 +7,7 @@ exports[`create non existing note hint renders a waiting message when button is
|
|||
data-testid="loadingMessage"
|
||||
role="alert"
|
||||
>
|
||||
<i
|
||||
class="fa fa-spinner fa-spin me-2 "
|
||||
/>
|
||||
BootstrapIconMock_ArrowRepeat
|
||||
noteLoadingBoundary.createNote.creating
|
||||
</div>
|
||||
</div>
|
||||
|
@ -62,10 +45,21 @@ exports[`create non existing note hint shows an error message if note couldn't b
|
|||
data-testid="failedMessage"
|
||||
role="alert"
|
||||
>
|
||||
<i
|
||||
class="fa fa-exclamation-triangle me-1 "
|
||||
/>
|
||||
BootstrapIconMock_ExclamationTriangle
|
||||
noteLoadingBoundary.createNote.error
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`create non existing note hint shows success message when the note has been created 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="fade mt-5 alert alert-info show"
|
||||
data-testid="noteCreated"
|
||||
role="alert"
|
||||
>
|
||||
BootstrapIconMock_CheckCircle
|
||||
noteLoadingBoundary.createNote.success
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
import { createNoteWithPrimaryAlias } from '../../../api/notes'
|
||||
import { useSingleStringUrlParameter } from '../../../hooks/common/use-single-string-url-parameter'
|
||||
import { testId } from '../../../utils/test-id'
|
||||
import { ForkAwesomeIcon } from '../fork-awesome/fork-awesome-icon'
|
||||
import { UiIcon } from '../icons/ui-icon'
|
||||
import { ShowIf } from '../show-if/show-if'
|
||||
import React, { useCallback, useEffect } from 'react'
|
||||
import { Alert, Button } from 'react-bootstrap'
|
||||
import { ArrowRepeat as IconArrowRepeat } from 'react-bootstrap-icons'
|
||||
import { CheckCircle as IconCheckCircle } from 'react-bootstrap-icons'
|
||||
import { ExclamationTriangle as IconExclamationTriangle } from 'react-bootstrap-icons'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { useAsyncFn } from 'react-use'
|
||||
|
||||
|
@ -49,21 +52,21 @@ export const CreateNonExistingNoteHint: React.FC<CreateNonExistingNoteHintProps>
|
|||
} else if (returnState.value) {
|
||||
return (
|
||||
<Alert variant={'info'} {...testId('noteCreated')} className={'mt-5'}>
|
||||
<ForkAwesomeIcon icon={'check-circle'} className={'me-2'} />
|
||||
<UiIcon icon={IconCheckCircle} className={'me-2'} />
|
||||
<Trans i18nKey={'noteLoadingBoundary.createNote.success'} />
|
||||
</Alert>
|
||||
)
|
||||
} else if (returnState.loading) {
|
||||
return (
|
||||
<Alert variant={'info'} {...testId('loadingMessage')} className={'mt-5'}>
|
||||
<ForkAwesomeIcon icon={'spinner'} className={'fa-spin me-2'} />
|
||||
<UiIcon icon={IconArrowRepeat} className={'me-2'} spin={true} />
|
||||
<Trans i18nKey={'noteLoadingBoundary.createNote.creating'} />
|
||||
</Alert>
|
||||
)
|
||||
} else if (returnState.error !== undefined) {
|
||||
return (
|
||||
<Alert variant={'danger'} {...testId('failedMessage')} className={'mt-5'}>
|
||||
<ForkAwesomeIcon icon={'exclamation-triangle'} className={'me-1'} />
|
||||
<UiIcon icon={IconExclamationTriangle} className={'me-1'} />
|
||||
<Trans i18nKey={'noteLoadingBoundary.createNote.error'} />
|
||||
</Alert>
|
||||
)
|
||||
|
@ -82,7 +85,7 @@ export const CreateNonExistingNoteHint: React.FC<CreateNonExistingNoteHintProps>
|
|||
onClick={onClickHandler}
|
||||
{...testId('createNoteButton')}>
|
||||
<ShowIf condition={returnState.loading}>
|
||||
<ForkAwesomeIcon icon={'spinner'} className={'fa-spin me-2'} />
|
||||
<UiIcon icon={IconArrowRepeat} className={'me-2'} spin={true} />
|
||||
</ShowIf>
|
||||
<Trans i18nKey={'noteLoadingBoundary.createNote.create'} />
|
||||
</Button>
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { ForkAwesomeIcon } from '../fork-awesome/fork-awesome-icon'
|
||||
import { UiIcon } from '../icons/ui-icon'
|
||||
import React from 'react'
|
||||
import { ArrowRepeat as IconArrowRepeat } from 'react-bootstrap-icons'
|
||||
|
||||
/**
|
||||
* Renders a indefinitely spinning spinner.
|
||||
|
@ -12,7 +13,7 @@ import React from 'react'
|
|||
export const WaitSpinner: React.FC = () => {
|
||||
return (
|
||||
<div className={'m-3 d-flex align-items-center justify-content-center'}>
|
||||
<ForkAwesomeIcon icon={'spinner'} className={'fa-spin'} />
|
||||
<UiIcon icon={IconArrowRepeat} spin={true} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue