Restructure repository (#426)

organized repository 

Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
Co-authored-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
Co-authored-by: Philip Molares <git@molar.es>
This commit is contained in:
mrdrogdrog 2020-08-16 16:02:26 +02:00 committed by GitHub
parent 66258ca615
commit 0fadc09f2b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
254 changed files with 384 additions and 403 deletions

View file

@ -1,28 +0,0 @@
import React, { Fragment } from 'react'
import { ShowIf } from '../show-if/show-if'
export interface ElementSeparatorProps {
separator: React.ReactElement
}
export const ElementSeparator: React.FC<ElementSeparatorProps> = ({ children, separator }) => {
return (
<Fragment>
{
React.Children
.toArray(children)
.filter(child => child !== null)
.map((child, index) => {
return (
<Fragment>
<ShowIf condition={index > 0}>
{separator}
</ShowIf>
{child}
</Fragment>
)
})
}
</Fragment>
)
}

View file

@ -1,42 +0,0 @@
.markdown-body {
@import '../../../../node_modules/highlight.js/styles/github-gist';
}
.markdown-body pre code.hljs {
padding: 16px;
display: grid;
grid-template-columns: auto minmax(0, 1fr);
&.showGutter {
.linenumber {
position: relative;
cursor: default;
z-index: 4;
padding: 0 8px 0 0;
min-width: 20px;
box-sizing: content-box;
color: #afafaf;
border-right: 3px solid #6ce26c;
flex-direction: column;
overflow: hidden;
user-select: none;
display: flex;
align-items: flex-end;
&:before {
content: attr(data-line-number);
}
}
}
&.showGutter .codeline {
margin: 0 0 0 16px;
}
&.wrapLines .codeline {
white-space: pre-wrap;
}
}

View file

@ -1,59 +0,0 @@
import hljs from 'highlight.js'
import React, { Fragment, useMemo } from 'react'
import ReactHtmlParser from 'react-html-parser'
import './highlighted-code.scss'
export interface HighlightedCodeProps {
code: string,
language?: string,
startLineNumber?: number
wrapLines: boolean
}
export const escapeHtml = (unsafe: string): string => {
return unsafe
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;')
}
const checkIfLanguageIsSupported = (language: string): boolean => {
return hljs.listLanguages().indexOf(language) > -1
}
const correctLanguage = (language: string | undefined): string | undefined => {
switch (language) {
case 'html':
return 'xml'
default:
return language
}
}
export const HighlightedCode: React.FC<HighlightedCodeProps> = ({ code, language, startLineNumber, wrapLines }) => {
const highlightedCode = useMemo(() => {
const replacedLanguage = correctLanguage(language)
return ((!!replacedLanguage && checkIfLanguageIsSupported(replacedLanguage)) ? hljs.highlight(replacedLanguage, code).value : escapeHtml(code))
.split('\n')
.filter(line => !!line)
.map(line => ReactHtmlParser(line))
}, [code, language])
return (
<code className={`hljs ${startLineNumber !== undefined ? 'showGutter' : ''} ${wrapLines ? 'wrapLines' : ''}`}>
{
highlightedCode
.map((line, index) => {
return <Fragment key={index}>
<span className={'linenumber'} data-line-number={(startLineNumber || 1) + index}/>
<div className={'codeline'}>
{line}
</div>
</Fragment>
})
}
</code>)
}

View file

@ -1,11 +1,17 @@
.btn-icon {
padding: 0.375rem 0.375rem;
border-right: 1px solid rgba(0, 0, 0, 0.2);
display: flex;
&.with-border {
.icon-part {
border-right: 1px solid rgba(0, 0, 0, 0.2);
}
.text-part {
padding: 0.375rem 0.75rem;
}
}
.icon-part {
padding: 0.375rem 0.375rem;
border-right: 1px solid rgba(0, 0, 0, 0.2);
display: flex;
.social-icon {
@ -14,7 +20,7 @@
}
.text-part {
padding: 0.375rem 0.75rem;
padding: 0.375rem 0.75rem 0.375rem 0;
}
}

View file

@ -3,15 +3,15 @@ import { Button, ButtonProps } from 'react-bootstrap'
import { ForkAwesomeIcon, IconName } from '../fork-awesome/fork-awesome-icon'
import './icon-button.scss'
export interface SocialButtonProps extends ButtonProps {
export interface IconButtonProps extends ButtonProps {
icon: IconName
onClick?: () => void
border?: boolean
}
export const IconButton: React.FC<SocialButtonProps> = ({ icon, children, variant, onClick }) => {
export const IconButton: React.FC<IconButtonProps> = ({ icon, children, border = false, ...props }) => {
return (
<Button variant={variant} className={'btn-icon p-0 d-inline-flex align-items-stretch'}
onClick={() => onClick?.()}>
<Button {...props} className={`btn-icon p-0 d-inline-flex align-items-stretch ${border ? 'with-border' : ''}`}>
<span className="icon-part d-flex align-items-center">
<ForkAwesomeIcon icon={icon} className={'icon'}/>
</span>

View file

@ -0,0 +1,16 @@
import React from 'react'
import { Trans } from 'react-i18next'
import './icon-button.scss'
import { IconButton, IconButtonProps } from './icon-button'
export interface TranslatedIconButton extends IconButtonProps {
i18nKey: string
}
export const TranslatedIconButton: React.FC<TranslatedIconButton> = ({ i18nKey, ...props }) => {
return (
<IconButton {...props}>
<Trans i18nKey={i18nKey}/>
</IconButton>
)
}

View file

@ -0,0 +1,34 @@
import React from 'react'
import { useSelector } from 'react-redux'
import { Link } from 'react-router-dom'
import { ApplicationState } from '../../../redux'
import { Alert, Button } from 'react-bootstrap'
import { setBanner } from '../../../redux/banner/methods'
import { ForkAwesomeIcon } from '../fork-awesome/fork-awesome-icon'
import { ShowIf } from '../show-if/show-if'
export const MotdBanner: React.FC = () => {
const bannerState = useSelector((state: ApplicationState) => state.banner)
const dismissBanner = () => {
setBanner({ ...bannerState, show: false })
window.localStorage.setItem('bannerTimeStamp', bannerState.timestamp)
}
return (
<ShowIf condition={bannerState.show}>
<Alert variant='primary' dir='auto' className='mb-0 text-center d-flex flex-row justify-content-center'>
<Link to='/s/banner' className='flex-grow-1 align-self-center'>
{bannerState.text}
</Link>
<Button
variant='outline-primary'
size='sm'
className='mx-2'
onClick={dismissBanner}>
<ForkAwesomeIcon icon='times'/>
</Button>
</Alert>
</ShowIf>
)
}

View file

@ -0,0 +1,12 @@
import React from 'react'
import { LandingLayout } from '../../landing-layout/landing-layout'
export const NotFoundErrorScreen: React.FC = () => {
return (
<LandingLayout>
<div className='text-white d-flex align-items-center justify-content-center my-5'>
<h1>404 Not Found <small>oops.</small></h1>
</div>
</LandingLayout>
)
}

View file

@ -0,0 +1,28 @@
import React, { useEffect, useState } from 'react'
import { Redirect } from 'react-router'
import { useParams } from 'react-router-dom'
import { getNote } from '../../../api/notes'
import { NotFoundErrorScreen } from './not-found-error-screen'
interface RouteParameters {
id: string
}
export const Redirector: React.FC = () => {
const { id } = useParams<RouteParameters>()
const [error, setError] = useState<boolean | null>(null)
useEffect(() => {
getNote(id)
.then((noteFromAPI) => setError(!noteFromAPI.preVersionTwoNote))
.catch(() => setError(true))
}, [id])
if (error) {
return (<NotFoundErrorScreen/>)
} else if (!error && error != null) {
return (<Redirect to={`/n/${id}`}/>)
} else {
return (<span>Loading</span>)
}
}

View file

@ -1,47 +0,0 @@
import React from 'react'
import { ButtonProps } from 'react-bootstrap'
import { IconName } from '../fork-awesome/fork-awesome-icon'
import { IconButton } from '../icon-button/icon-button'
export enum SortModeEnum {
up = 1,
down = -1,
no = 0
}
const getIcon = (direction: SortModeEnum): IconName => {
switch (direction) {
default:
case SortModeEnum.no:
return 'sort'
case SortModeEnum.up:
return 'sort-asc'
case SortModeEnum.down:
return 'sort-desc'
}
}
export interface SortButtonProps extends ButtonProps {
onDirectionChange: (direction: SortModeEnum) => void
direction: SortModeEnum
}
const toggleDirection = (direction: SortModeEnum) => {
switch (direction) {
case SortModeEnum.no:
return SortModeEnum.up
case SortModeEnum.up:
return SortModeEnum.down
default:
case SortModeEnum.down:
return SortModeEnum.no
}
}
export const SortButton: React.FC<SortButtonProps> = ({ children, variant, onDirectionChange, direction }) => {
const toggleSort = () => {
onDirectionChange(toggleDirection(direction))
}
return <IconButton onClick={toggleSort} variant={variant} icon={getIcon(direction)}>{children}</IconButton>
}

View file

@ -1,7 +0,0 @@
.split-divider {
width: 10px;
background: white;
z-index: 1;
cursor: col-resize;
box-shadow: 3px 0 6px #e7e7e7;
}

View file

@ -1,15 +0,0 @@
import React from 'react'
import './split-divider.scss'
export interface SplitDividerProps {
onGrab: () => void
}
export const SplitDivider: React.FC<SplitDividerProps> = ({ onGrab }) => {
return (
<div
onMouseDown={() => onGrab()}
onTouchStart={() => onGrab()}
className={'split-divider'}/>
)
}

View file

@ -1,14 +0,0 @@
.splitter {
&.left {
flex: 0 1 100%;
min-width: 200px;
}
&.right {
flex: 1 0 200px;
}
&.separator {
display: flex;
}
}

View file

@ -1,63 +0,0 @@
import React, { ReactElement, useRef, useState } from 'react'
import { ShowIf } from '../show-if/show-if'
import { SplitDivider } from '../split-divider/split-divider'
import './splitter.scss'
export interface SplitterProps {
left: ReactElement
right: ReactElement
containerClassName?: string
showLeft: boolean
showRight: boolean
}
export const Splitter: React.FC<SplitterProps> = ({ containerClassName, left, right, showLeft, showRight }) => {
const [split, setSplit] = useState(50)
const realSplit = Math.max(0, Math.min(100, (showRight ? split : 100)))
const [doResizing, setDoResizing] = useState(false)
const splitContainer = useRef<HTMLDivElement>(null)
const recalculateSize = (mouseXPosition: number): void => {
if (!splitContainer.current) {
return
}
const x = mouseXPosition - splitContainer.current.offsetLeft
const newSize = x / splitContainer.current.clientWidth
setSplit(newSize * 100)
}
return (
<div ref={splitContainer} className={`flex-fill flex-row d-flex ${containerClassName || ''}`}
onMouseUp={() => setDoResizing(false)}
onTouchEnd={() => setDoResizing(false)}
onMouseMove={(mouseEvent) => {
if (doResizing) {
recalculateSize(mouseEvent.pageX)
mouseEvent.preventDefault()
}
}}
onTouchMove={(touchEvent) => {
if (doResizing) {
recalculateSize(touchEvent.touches[0].pageX)
}
}}
>
<ShowIf condition={showLeft}>
<div className={'splitter left'} style={{ flexBasis: `calc(${realSplit}% - 5px)` }}>
{left}
</div>
</ShowIf>
<ShowIf condition={showLeft && showRight}>
<div className='splitter separator'>
<SplitDivider onGrab={() => setDoResizing(true)}/>
</div>
</ShowIf>
<ShowIf condition={showRight}>
<div className='splitter right'>
{right}
</div>
</ShowIf>
</div>
)
}

View file

@ -0,0 +1,8 @@
.user-avatar {
width: 20px;
height: 20px;
}
.user-name {
font-size: 1rem;
}

View file

@ -0,0 +1,30 @@
import React from 'react'
import { useTranslation } from 'react-i18next'
import { ShowIf } from '../show-if/show-if'
import './user-avatar.scss'
export interface UserAvatarProps {
name: string;
photo: string;
additionalClasses?: string;
showName?: boolean
}
const UserAvatar: React.FC<UserAvatarProps> = ({ name, photo, additionalClasses = '', showName = true }) => {
const { t } = useTranslation()
return (
<span className={'d-inline-flex align-items-center ' + additionalClasses}>
<img
src={photo}
className="user-avatar rounded"
alt={t('common.avatarOf', { name })}
/>
<ShowIf condition={showName}>
<span className="mx-1 user-name">{name}</span>
</ShowIf>
</span>
)
}
export { UserAvatar }