mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-06-06 09:31:35 -04:00
imported current state of the mockup into the public repo
Co-authored-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de> Signed-off-by: Philip Molares <philip.molares@udo.edu> Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
This commit is contained in:
commit
93ce059577
161 changed files with 17419 additions and 0 deletions
21
src/components/landing/pages/history/common/button.scss
Normal file
21
src/components/landing/pages/history/common/button.scss
Normal file
|
@ -0,0 +1,21 @@
|
|||
.history-pin {
|
||||
opacity: 0.2;
|
||||
transition: opacity 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #d43f3a;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.history-close {
|
||||
opacity: 0.5;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
13
src/components/landing/pages/history/common/close-button.tsx
Normal file
13
src/components/landing/pages/history/common/close-button.tsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||
import React from "react";
|
||||
|
||||
const CloseButton: React.FC = () => {
|
||||
return (
|
||||
<FontAwesomeIcon
|
||||
className="history-close"
|
||||
icon="times"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export { CloseButton }
|
19
src/components/landing/pages/history/common/pin-button.tsx
Normal file
19
src/components/landing/pages/history/common/pin-button.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||
import React from "react";
|
||||
|
||||
export interface PinButtonProps {
|
||||
pin: boolean;
|
||||
onPinChange: () => void;
|
||||
}
|
||||
|
||||
const PinButton: React.FC<PinButtonProps> = ({pin, onPinChange}) => {
|
||||
return (
|
||||
<FontAwesomeIcon
|
||||
icon="thumbtack"
|
||||
className={`history-pin ${pin? 'active' : ''}`}
|
||||
onClick={onPinChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export { PinButton }
|
|
@ -0,0 +1,33 @@
|
|||
import React from 'react'
|
||||
import {HistoryInput} from '../history'
|
||||
import {Badge, Card} from 'react-bootstrap'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'
|
||||
import {format, formatDistance} from 'date-fns'
|
||||
import "../common/button.scss"
|
||||
import {PinButton} from "../common/pin-button";
|
||||
import {CloseButton} from "../common/close-button";
|
||||
|
||||
export const HistoryCard: React.FC<HistoryInput> = ({pinned, title, lastVisited, tags, onPinChange}) => {
|
||||
return (
|
||||
<div className="p-2 col-xs-12 col-sm-6 col-md-6 col-lg-4">
|
||||
<Card className="p-0" text={"dark"} bg={"light"}>
|
||||
<div className="d-flex justify-content-between p-2">
|
||||
<PinButton pin={pinned} onPinChange={onPinChange}/>
|
||||
<Card.Title className="m-0 mt-3">{title}</Card.Title>
|
||||
<CloseButton/>
|
||||
</div>
|
||||
<Card.Body>
|
||||
<div className="text-black-50">
|
||||
<FontAwesomeIcon icon="clock"/> {formatDistance(lastVisited, new Date())}<br/>
|
||||
{format(lastVisited, 'EEE, LLL d, YYY h:mm a')}
|
||||
<div children=
|
||||
{
|
||||
tags.map((tag) => <Badge variant={"dark"} key={tag}>{tag}</Badge>)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import React from "react";
|
||||
import {HistoryInput} from "../history";
|
||||
import {format} from "date-fns";
|
||||
import {PinButton} from "../common/pin-button";
|
||||
import {CloseButton} from "../common/close-button";
|
||||
|
||||
export const HistoryTableRow: React.FC<HistoryInput> = ({pinned, title, lastVisited, onPinChange}) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{title}</td>
|
||||
<td>{format(lastVisited, 'EEE, LLL d, YYY h:mm a')}</td>
|
||||
<td>
|
||||
<PinButton pin={pinned} onPinChange={onPinChange}/>
|
||||
|
||||
<CloseButton/>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import React from "react";
|
||||
import {Table} from "react-bootstrap"
|
||||
|
||||
const HistoryTable: React.FC = ({children}) => {
|
||||
return (
|
||||
<Table striped bordered hover size="sm" variant="dark">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Last visited</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{children}
|
||||
</tbody>
|
||||
</Table>
|
||||
)
|
||||
}
|
||||
|
||||
export { HistoryTable }
|
103
src/components/landing/pages/history/history.tsx
Normal file
103
src/components/landing/pages/history/history.tsx
Normal file
|
@ -0,0 +1,103 @@
|
|||
import React, {Fragment, useEffect, useState} from 'react'
|
||||
import {HistoryCard} from "./history-card/history-card";
|
||||
import {HistoryTable} from "./history-table/history-table";
|
||||
import {HistoryTableRow} from './history-table/history-table-row';
|
||||
import {ToggleButton, ToggleButtonGroup} from 'react-bootstrap';
|
||||
|
||||
interface HistoryChange {
|
||||
onPinChange: () => void,
|
||||
}
|
||||
|
||||
interface ViewState {
|
||||
viewState: ViewStateEnum
|
||||
}
|
||||
|
||||
enum ViewStateEnum {
|
||||
card,
|
||||
table
|
||||
}
|
||||
|
||||
export type HistoryInput = HistoryEntry & HistoryChange
|
||||
|
||||
interface HistoryEntry {
|
||||
id: string,
|
||||
title: string,
|
||||
lastVisited: Date,
|
||||
tags: string[],
|
||||
pinned: boolean
|
||||
}
|
||||
|
||||
function loadHistoryFromLocalStore() {
|
||||
const historyJsonString = window.localStorage.getItem("notehistory");
|
||||
return historyJsonString ? JSON.parse(historyJsonString) : [];
|
||||
}
|
||||
|
||||
const History: React.FC = () => {
|
||||
const [historyEntries, setHistoryEntries] = useState<HistoryEntry[]>([])
|
||||
const [viewState, setViewState] = useState<ViewState>({
|
||||
viewState: ViewStateEnum.card
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
let history = loadHistoryFromLocalStore();
|
||||
setHistoryEntries(history);
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<h1>History</h1>
|
||||
<ToggleButtonGroup type="radio" name="options" defaultValue={ViewStateEnum.card} className="mb-2"
|
||||
onChange={(newState: ViewStateEnum) => setViewState(() => ({viewState: newState}))}>
|
||||
<ToggleButton value={ViewStateEnum.card}>Card</ToggleButton>
|
||||
<ToggleButton value={ViewStateEnum.table}>Table</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
{
|
||||
viewState.viewState === ViewStateEnum.card ? (
|
||||
<div className="d-flex flex-wrap">
|
||||
{
|
||||
historyEntries.length === 0 ?
|
||||
''
|
||||
:
|
||||
historyEntries.map((entry) =>
|
||||
<HistoryCard
|
||||
id={entry.id}
|
||||
tags={entry.tags}
|
||||
pinned={entry.pinned}
|
||||
title={entry.title}
|
||||
lastVisited={entry.lastVisited}
|
||||
onPinChange={() => {
|
||||
// setHistoryEntries((prev: HistoryEntry) => {
|
||||
// return {...prev, pinned: !prev.pinned};
|
||||
// });
|
||||
}}
|
||||
/>)
|
||||
}
|
||||
</div>
|
||||
) : (
|
||||
<HistoryTable>
|
||||
{
|
||||
historyEntries.length === 0 ?
|
||||
''
|
||||
:
|
||||
historyEntries.map((entry) =>
|
||||
<HistoryTableRow
|
||||
id={entry.id}
|
||||
tags={entry.tags}
|
||||
pinned={entry.pinned}
|
||||
title={entry.title}
|
||||
lastVisited={entry.lastVisited}
|
||||
onPinChange={() => {
|
||||
// setEntry((prev: HistoryEntry) => {
|
||||
// return {...prev, pinned: !prev.pinned};
|
||||
// });
|
||||
}}
|
||||
/>)
|
||||
}
|
||||
</HistoryTable>
|
||||
)
|
||||
}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
export {History}
|
BIN
src/components/landing/pages/intro/img/screenshot.png
Normal file
BIN
src/components/landing/pages/intro/img/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 222 KiB |
82
src/components/landing/pages/intro/intro.tsx
Normal file
82
src/components/landing/pages/intro/intro.tsx
Normal file
|
@ -0,0 +1,82 @@
|
|||
import React from 'react'
|
||||
import screenshot from './img/screenshot.png';
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||
import {Button} from 'react-bootstrap';
|
||||
import {Trans, useTranslation} from "react-i18next";
|
||||
import {Link} from "react-router-dom";
|
||||
|
||||
const Intro: React.FC = () => {
|
||||
// ToDo replace this with comment
|
||||
const url = "http://localhost:3000";//useServerUrl();
|
||||
useTranslation();
|
||||
|
||||
return (
|
||||
<div id="home" className="section">
|
||||
<div className="inner cover">
|
||||
<h1 className="cover-heading">
|
||||
<FontAwesomeIcon icon="file-alt"/> CodiMD
|
||||
</h1>
|
||||
<p className="lead mb-5">
|
||||
<Trans i18nKey="slogan"/>
|
||||
</p>
|
||||
|
||||
<div className="mb-5">
|
||||
<Link to="/login">
|
||||
<Button
|
||||
variant="success"
|
||||
size="lg"
|
||||
style={{minWidth: "200px"}}
|
||||
>
|
||||
<Trans i18nKey="signIn"/>
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
|
||||
<span className="m-2">
|
||||
or
|
||||
</span>
|
||||
|
||||
<Button
|
||||
variant="primary"
|
||||
size="lg"
|
||||
href={`${url}/features`}
|
||||
style={{minWidth: "200px"}}
|
||||
>
|
||||
<Trans i18nKey="exploreFeatures"/>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<img alt="CodiMD Screenshot" src={screenshot} className="screenshot img-fluid mb-5"/>
|
||||
|
||||
<div className="lead row mb-5" style={{width: '90%', margin: '0 auto'}}>
|
||||
<div className="col-md-4 inner">
|
||||
<a href={`${url}/features#Share-Notes`} className="text-light">
|
||||
<FontAwesomeIcon icon="bolt" size="3x"/>
|
||||
<h5>
|
||||
<Trans i18nKey="featureCollaboration"/>
|
||||
</h5>
|
||||
</a>
|
||||
</div>
|
||||
<div className="col-md-4 inner">
|
||||
<a href={`${url}/features#MathJax`} className="text-light">
|
||||
<FontAwesomeIcon icon="chart-bar" size="3x"/>
|
||||
<h5>
|
||||
<Trans i18nKey="featureMathJax"/>
|
||||
</h5>
|
||||
</a>
|
||||
</div>
|
||||
<div className="col-md-4 inner">
|
||||
<a href={`${url}/features#Slide-Mode`} className="text-light">
|
||||
<FontAwesomeIcon icon="tv" size="3x"/>
|
||||
<h5>
|
||||
<Trans i18nKey="featureSlides"/>
|
||||
</h5>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export {Intro}
|
|
@ -0,0 +1,48 @@
|
|||
.btn.btn-icon {
|
||||
color: #FFFFFF;
|
||||
|
||||
@mixin button($color) {
|
||||
background-color: $color;
|
||||
&:hover {
|
||||
background-color: darken($color, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
&.btn-social-dropbox {
|
||||
@include button(#1087DD);
|
||||
}
|
||||
|
||||
&.btn-social-facebook {
|
||||
@include button(#3B5998);
|
||||
}
|
||||
|
||||
&.btn-social-github {
|
||||
@include button(#444444);
|
||||
}
|
||||
|
||||
&.btn-social-gitlab {
|
||||
@include button(#FA7035);
|
||||
}
|
||||
|
||||
&.btn-social-google {
|
||||
@include button(#DD4B39);
|
||||
}
|
||||
|
||||
&.btn-social-twitter {
|
||||
@include button(#55ACEE);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-social-button {
|
||||
padding: 0.375rem 0.375rem;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.2);
|
||||
display: flex;
|
||||
|
||||
.social-icon {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-social-text {
|
||||
padding: 0.375rem 0.75rem;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import React from "react";
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||
import "./icon-button.scss";
|
||||
import {IconProp} from "@fortawesome/fontawesome-svg-core";
|
||||
|
||||
export interface SocialButtonProps {
|
||||
backgroundClass: string,
|
||||
href: string
|
||||
icon: IconProp
|
||||
title?: string
|
||||
}
|
||||
|
||||
export const IconButton: React.FC<SocialButtonProps> = ({title, backgroundClass, href, icon, children}) => {
|
||||
return (
|
||||
<a href={href} title={title}
|
||||
className={"btn btn-icon p-0 d-inline-flex align-items-stretch " + backgroundClass}>
|
||||
<span className="btn-social-button d-flex align-items-center">
|
||||
<FontAwesomeIcon icon={icon} className={"social-icon"}/>
|
||||
</span>
|
||||
<span className="btn-social-text d-flex align-items-center">
|
||||
{children}
|
||||
</span>
|
||||
</a>
|
||||
)
|
||||
}
|
39
src/components/landing/pages/login/auth/via-email.tsx
Normal file
39
src/components/landing/pages/login/auth/via-email.tsx
Normal file
|
@ -0,0 +1,39 @@
|
|||
import {Trans, useTranslation} from "react-i18next";
|
||||
import {Button, Form} from "react-bootstrap";
|
||||
import React, { Fragment } from "react";
|
||||
import {useDispatch} from "react-redux";
|
||||
import {setUser} from "../../../../../redux/user/actions";
|
||||
import {LoginStatus} from "../../../../../redux/user/types";
|
||||
|
||||
const ViaEMail: React.FC = () => {
|
||||
useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const login = () => {
|
||||
dispatch(setUser({photo: "https://robohash.org/testy.png", name: "Test", status: LoginStatus.ok}));
|
||||
}
|
||||
return (
|
||||
<Fragment>
|
||||
<h5 className="center">
|
||||
<Trans i18nKey="signInVia" values={{service: "E-Mail"}}/>
|
||||
</h5>
|
||||
<Form>
|
||||
<Form.Group controlId="formBasicEmail">
|
||||
<Form.Control type="email" size="sm" placeholder="E-Mail" />
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group controlId="formBasicPassword">
|
||||
<Form.Control type="password" size="sm" placeholder="Password" />
|
||||
</Form.Group>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="primary"
|
||||
onClick={login}
|
||||
>
|
||||
<Trans i18nKey="signIn"/>
|
||||
</Button>
|
||||
</Form>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export { ViaEMail }
|
30
src/components/landing/pages/login/auth/via-ldap.tsx
Normal file
30
src/components/landing/pages/login/auth/via-ldap.tsx
Normal file
|
@ -0,0 +1,30 @@
|
|||
import React, {Fragment} from "react";
|
||||
import {Trans} from "react-i18next";
|
||||
import {Button, Form} from "react-bootstrap";
|
||||
|
||||
const ViaLdap: React.FC = () => {
|
||||
return (
|
||||
<Fragment>
|
||||
<h5 className="center">
|
||||
<Trans i18nKey="signInVia" values={{service: "LDAP"}}/>
|
||||
</h5>
|
||||
<Form>
|
||||
<Form.Group controlId="formBasicUsername">
|
||||
<Form.Control type="text" size="sm" placeholder="Username" />
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group controlId="formBasicPassword">
|
||||
<Form.Control type="password" size="sm" placeholder="Password" />
|
||||
</Form.Group>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="primary"
|
||||
>
|
||||
<Trans i18nKey="signIn"/>
|
||||
</Button>
|
||||
</Form>
|
||||
</Fragment>
|
||||
)
|
||||
};
|
||||
|
||||
export { ViaLdap }
|
115
src/components/landing/pages/login/auth/via-oauth2.tsx
Normal file
115
src/components/landing/pages/login/auth/via-oauth2.tsx
Normal file
|
@ -0,0 +1,115 @@
|
|||
import React from "react";
|
||||
import {IconProp} from "@fortawesome/fontawesome-svg-core";
|
||||
import {IconButton} from "./icon-button/icon-button";
|
||||
|
||||
export enum OAuth2Type {
|
||||
'DROPBOX'="dropbox",
|
||||
'FACEBOOK'="facebook",
|
||||
'GITHUB'="github",
|
||||
'GITLAB'="gitlab",
|
||||
'GOOGLE'="google",
|
||||
'OAUTH2'="oauth2",
|
||||
'SAML'="saml",
|
||||
'TWITTER'="twitter"
|
||||
}
|
||||
|
||||
type OAuth2Map = (oauth2type: OAuth2Type) => {
|
||||
name: string,
|
||||
icon: IconProp,
|
||||
className: string,
|
||||
url: string
|
||||
};
|
||||
|
||||
const buildBackendAuthUrl = (backendName: string) => {
|
||||
return `https://localhost:3000/auth/${backendName}`
|
||||
};
|
||||
|
||||
const getMetadata: OAuth2Map = (oauth2type: OAuth2Type) => {
|
||||
switch (oauth2type) {
|
||||
case OAuth2Type.DROPBOX:
|
||||
return {
|
||||
name: "Dropbox",
|
||||
icon: ["fab", "dropbox"],
|
||||
className: "btn-social-dropbox",
|
||||
url: buildBackendAuthUrl("dropbox")
|
||||
}
|
||||
case OAuth2Type.FACEBOOK:
|
||||
return {
|
||||
name: "Facebook",
|
||||
icon: ["fab", "facebook"],
|
||||
className: "btn-social-facebook",
|
||||
url: buildBackendAuthUrl("facebook")
|
||||
}
|
||||
case OAuth2Type.GITHUB:
|
||||
return {
|
||||
name: "GitHub",
|
||||
icon: ["fab", "github"],
|
||||
className: "btn-social-github",
|
||||
url: buildBackendAuthUrl("github")
|
||||
}
|
||||
case OAuth2Type.GITLAB:
|
||||
return {
|
||||
name: "GitLab",
|
||||
icon: ["fab", "gitlab"],
|
||||
className: "btn-social-gitlab",
|
||||
url: buildBackendAuthUrl("gitlab")
|
||||
}
|
||||
case OAuth2Type.GOOGLE:
|
||||
return {
|
||||
name: "Google",
|
||||
icon: ["fab", "google"],
|
||||
className: "btn-social-google",
|
||||
url: buildBackendAuthUrl("google")
|
||||
}
|
||||
case OAuth2Type.OAUTH2:
|
||||
return {
|
||||
name: "oAuth2",
|
||||
icon: "share",
|
||||
className: "btn-primary",
|
||||
url: buildBackendAuthUrl("oauth2")
|
||||
}
|
||||
case OAuth2Type.SAML:
|
||||
return {
|
||||
name: "SAML",
|
||||
icon: "users",
|
||||
className: "btn-success",
|
||||
url: buildBackendAuthUrl("saml")
|
||||
}
|
||||
case OAuth2Type.TWITTER:
|
||||
return {
|
||||
name: "Twitter",
|
||||
icon: ["fab", "twitter"],
|
||||
className: "btn-social-twitter",
|
||||
url: buildBackendAuthUrl("twitter")
|
||||
}
|
||||
default:
|
||||
return {
|
||||
name: "",
|
||||
icon: "exclamation",
|
||||
className: "",
|
||||
url: "#"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface ViaOAuth2Props {
|
||||
oauth2Type: OAuth2Type;
|
||||
optionalName?: string;
|
||||
}
|
||||
|
||||
const ViaOAuth2: React.FC<ViaOAuth2Props> = ({oauth2Type, optionalName}) => {
|
||||
const {name, icon, className, url} = getMetadata(oauth2Type);
|
||||
const text = !!optionalName ? optionalName : name;
|
||||
return (
|
||||
<IconButton
|
||||
backgroundClass={className}
|
||||
icon={icon}
|
||||
href={url}
|
||||
title={text}
|
||||
>
|
||||
{text}
|
||||
</IconButton>
|
||||
)
|
||||
}
|
||||
|
||||
export {ViaOAuth2}
|
56
src/components/landing/pages/login/login.tsx
Normal file
56
src/components/landing/pages/login/login.tsx
Normal file
|
@ -0,0 +1,56 @@
|
|||
import React from "react"
|
||||
import {Col, Jumbotron, Row} from "react-bootstrap"
|
||||
import {Trans, useTranslation} from "react-i18next";
|
||||
import {ViaEMail} from "./auth/via-email";
|
||||
import {OAuth2Type, ViaOAuth2} from "./auth/via-oauth2";
|
||||
import {ViaLdap} from "./auth/via-ldap";
|
||||
import {useSelector} from "react-redux";
|
||||
import {ApplicationState} from "../../../../redux";
|
||||
|
||||
const Login: React.FC = () => {
|
||||
useTranslation();
|
||||
const authProviders = useSelector((state: ApplicationState) => state.applicationConfig.authProviders);
|
||||
|
||||
const emailForm = authProviders.email ? <ViaEMail/> : null
|
||||
const ldapForm = authProviders.ldap ? <ViaLdap/> : null
|
||||
const emailLdapSeperator = authProviders.email && authProviders.ldap ? <hr className="w-100 bg-white"/> : null
|
||||
|
||||
return (
|
||||
<Jumbotron className="bg-dark">
|
||||
<div className="my-3">
|
||||
<Row className="h-100 flex justify-content-center">
|
||||
{
|
||||
authProviders.email || authProviders.ldap ?
|
||||
<Col xs={12} sm={10} lg={3}>
|
||||
{emailForm}
|
||||
{emailLdapSeperator}
|
||||
{ldapForm}
|
||||
<hr className="w-100 d-lg-none d-block bg-white"/>
|
||||
</Col>
|
||||
: null
|
||||
}
|
||||
<Col xs={12} sm={10} lg={5}>
|
||||
<h5>
|
||||
<Trans i18nKey="signInVia" values={{service: ""}}/>
|
||||
</h5>
|
||||
<div className={"d-flex flex-wrap one-click-login justify-content-center"}>
|
||||
{
|
||||
Object.values(OAuth2Type)
|
||||
.filter((value) => authProviders[value])
|
||||
.map((value) => {
|
||||
return (
|
||||
<Col xs={12} md={4} className="p-2 d-flex flex-column">
|
||||
<ViaOAuth2 oauth2Type={value}/>
|
||||
</Col>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Jumbotron>
|
||||
)
|
||||
}
|
||||
|
||||
export {Login}
|
Loading…
Add table
Add a link
Reference in a new issue