mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-19 01:35:18 -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
|
@ -0,0 +1,44 @@
|
|||
import {useDispatch} from "react-redux";
|
||||
import React from "react";
|
||||
import {getConfig} from "../../api/config";
|
||||
import {ApplicationConfigState} from "../../redux/application-config/types";
|
||||
import {setApplicationConfig} from "../../redux/application-config/actions";
|
||||
|
||||
const InitializeConfigStateFromApi: React.FC = () => {
|
||||
const dispatch = useDispatch();
|
||||
getConfig()
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
return (response.json() as Promise<ApplicationConfigState>);
|
||||
}
|
||||
})
|
||||
.then(config => {
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
dispatch(setApplicationConfig({
|
||||
allowAnonymous: config.allowAnonymous,
|
||||
authProviders: {
|
||||
facebook: config.authProviders.facebook,
|
||||
github: config.authProviders.github,
|
||||
twitter: config.authProviders.twitter,
|
||||
gitlab: config.authProviders.gitlab,
|
||||
dropbox: config.authProviders.dropbox,
|
||||
ldap: config.authProviders.ldap,
|
||||
google: config.authProviders.google,
|
||||
saml: config.authProviders.saml,
|
||||
oauth2: config.authProviders.oauth2,
|
||||
email: config.authProviders.email
|
||||
},
|
||||
specialLinks: {
|
||||
privacy: config.specialLinks.privacy,
|
||||
termsOfUse: config.specialLinks.termsOfUse,
|
||||
imprint: config.specialLinks.imprint,
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export { InitializeConfigStateFromApi }
|
30
src/components/initialize/initialize-user-state-from-api.tsx
Normal file
30
src/components/initialize/initialize-user-state-from-api.tsx
Normal file
|
@ -0,0 +1,30 @@
|
|||
import {useDispatch} from "react-redux";
|
||||
import {getMe} from "../../api/user";
|
||||
import {setUser} from "../../redux/user/actions";
|
||||
import {LoginStatus, UserState} from "../../redux/user/types";
|
||||
import React from "react";
|
||||
|
||||
const InitializeUserStateFromApi: React.FC = () => {
|
||||
const dispatch = useDispatch();
|
||||
getMe()
|
||||
.then((me) => {
|
||||
if (me.status === 200) {
|
||||
return (me.json() as Promise<UserState>);
|
||||
}
|
||||
})
|
||||
.then(user => {
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
dispatch(setUser({
|
||||
status: LoginStatus.ok,
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
photo: user.photo,
|
||||
}));
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export { InitializeUserStateFromApi }
|
28
src/components/landing/layout/footer/external-link.tsx
Normal file
28
src/components/landing/layout/footer/external-link.tsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
import React, {Fragment} from "react";
|
||||
import {IconProp} from "@fortawesome/fontawesome-svg-core";
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||
|
||||
export interface ExternalLinkProp {
|
||||
href: string;
|
||||
text: string;
|
||||
icon?: IconProp;
|
||||
}
|
||||
|
||||
export const ExternalLink: React.FC<ExternalLinkProp> = ({href, text, icon}) => {
|
||||
return (
|
||||
<a href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-light">
|
||||
{
|
||||
icon ?
|
||||
<Fragment>
|
||||
<FontAwesomeIcon icon={icon}/>
|
||||
</Fragment>
|
||||
:
|
||||
null
|
||||
}
|
||||
{text}
|
||||
</a>
|
||||
)
|
||||
}
|
14
src/components/landing/layout/footer/footer.tsx
Normal file
14
src/components/landing/layout/footer/footer.tsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import React from "react";
|
||||
import {LanguagePicker} from "./language-picker";
|
||||
import {PoweredByLinks} from "./powered-by-links";
|
||||
import {SocialLink} from "./social-links";
|
||||
|
||||
export const Footer: React.FC = () => {
|
||||
return (
|
||||
<footer>
|
||||
<LanguagePicker/>
|
||||
<PoweredByLinks/>
|
||||
<SocialLink/>
|
||||
</footer>
|
||||
);
|
||||
}
|
45
src/components/landing/layout/footer/language-picker.tsx
Normal file
45
src/components/landing/layout/footer/language-picker.tsx
Normal file
|
@ -0,0 +1,45 @@
|
|||
import React from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
|
||||
const LanguagePicker: React.FC = () => {
|
||||
const {i18n} = useTranslation();
|
||||
|
||||
const onChangeLang = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
i18n.changeLanguage(event.currentTarget.value);
|
||||
}
|
||||
|
||||
return (
|
||||
<select className="ui-locale" value={i18n.language} onChange={onChangeLang}>
|
||||
<option value="en">English</option>
|
||||
<option value="zh-CN">简体中文</option>
|
||||
<option value="zh-TW">繁體中文</option>
|
||||
<option value="fr">Français</option>
|
||||
<option value="de">Deutsch</option>
|
||||
<option value="ja">日本語</option>
|
||||
<option value="es">Español</option>
|
||||
<option value="ca">Català</option>
|
||||
<option value="el">Ελληνικά</option>
|
||||
<option value="pt">Português</option>
|
||||
<option value="it">Italiano</option>
|
||||
<option value="tr">Türkçe</option>
|
||||
<option value="ru">Русский</option>
|
||||
<option value="nl">Nederlands</option>
|
||||
<option value="hr">Hrvatski</option>
|
||||
<option value="pl">Polski</option>
|
||||
<option value="uk">Українська</option>
|
||||
<option value="hi">हिन्दी</option>
|
||||
<option value="sv">Svenska</option>
|
||||
<option value="eo">Esperanto</option>
|
||||
<option value="da">Dansk</option>
|
||||
<option value="ko">한국어</option>
|
||||
<option value="id">Bahasa Indonesia</option>
|
||||
<option value="sr">Cрпски</option>
|
||||
<option value="vi">Tiếng Việt</option>
|
||||
<option value="ar">العربية</option>
|
||||
<option value="cs">Česky</option>
|
||||
<option value="sk">Slovensky</option>
|
||||
</select>
|
||||
)
|
||||
}
|
||||
|
||||
export { LanguagePicker }
|
51
src/components/landing/layout/footer/powered-by-links.tsx
Normal file
51
src/components/landing/layout/footer/powered-by-links.tsx
Normal file
|
@ -0,0 +1,51 @@
|
|||
import {Trans, useTranslation} from "react-i18next";
|
||||
import {TranslatedLink} from "./translated-link";
|
||||
import React, {Fragment} from "react";
|
||||
import {ExternalLink} from "./external-link";
|
||||
import {useSelector} from "react-redux";
|
||||
import {ApplicationState} from "../../../../redux";
|
||||
|
||||
const PoweredByLinks: React.FC = () => {
|
||||
useTranslation();
|
||||
const defaultLinks = [
|
||||
{
|
||||
href: '/s/release-notes',
|
||||
i18nKey: 'releases'
|
||||
},
|
||||
{
|
||||
href: 'https://github.com/codimd/server/tree/41b13e71b6b1d499238c04b15d65e3bd76442f1d',
|
||||
i18nKey: 'sourceCode'
|
||||
}
|
||||
]
|
||||
|
||||
const config = useSelector((state: ApplicationState) => state.applicationConfig);
|
||||
|
||||
const specialLinks = Object.entries(config.specialLinks)
|
||||
.filter(([_, value]) => value !== "")
|
||||
.map(([key, value]) => {
|
||||
return {
|
||||
href: value,
|
||||
i18nKey: key
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<p>
|
||||
<Trans i18nKey="poweredBy" components={[<ExternalLink href="https://codimd.org" text="CodiMD"/>]}/>
|
||||
|
||||
{
|
||||
(defaultLinks.concat(specialLinks)).map(({href, i18nKey}) =>
|
||||
<Fragment key={i18nKey}>
|
||||
|
|
||||
<TranslatedLink
|
||||
href={href}
|
||||
i18nKey={i18nKey}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
export { PoweredByLinks }
|
20
src/components/landing/layout/footer/social-links.tsx
Normal file
20
src/components/landing/layout/footer/social-links.tsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
import React from "react";
|
||||
import {Trans, useTranslation} from "react-i18next";
|
||||
import {ExternalLink} from "./external-link";
|
||||
|
||||
const SocialLink: React.FC = () => {
|
||||
useTranslation();
|
||||
return (
|
||||
<p>
|
||||
<Trans i18nKey="followUs" components={[
|
||||
<ExternalLink href="https://github.com/codimd/server" icon={['fab', 'github']} text="GitHub"/>,
|
||||
<ExternalLink href="https://community.codimd.org" icon={['fab', 'discourse']} text="Discourse"/>,
|
||||
<ExternalLink href="https://riot.im/app/#/room/#codimd:matrix.org" icon="comment" text="Riot"/>,
|
||||
<ExternalLink href="https://social.codimd.org/mastodon" icon={['fab', 'mastodon']} text="Mastodon"/>,
|
||||
<ExternalLink href="https://translate.codimd.org" icon="globe" text="POEditor"/>
|
||||
]}/>
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
export { SocialLink }
|
21
src/components/landing/layout/footer/translated-link.tsx
Normal file
21
src/components/landing/layout/footer/translated-link.tsx
Normal file
|
@ -0,0 +1,21 @@
|
|||
import React from "react";
|
||||
import {Trans, useTranslation} from "react-i18next";
|
||||
|
||||
export interface TranslatedLinkProps {
|
||||
href: string;
|
||||
i18nKey: string;
|
||||
}
|
||||
|
||||
const TranslatedLink: React.FC<TranslatedLinkProps> = ({href, i18nKey}) => {
|
||||
useTranslation();
|
||||
return (
|
||||
<a href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-light">
|
||||
<Trans i18nKey={i18nKey}/>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
export {TranslatedLink}
|
28
src/components/landing/layout/index.tsx
Normal file
28
src/components/landing/layout/index.tsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
import React from "react";
|
||||
import {Route, Switch} from "react-router-dom";
|
||||
import {History} from "../pages/history/history";
|
||||
import {Intro} from "../pages/intro/intro";
|
||||
import {Container} from "react-bootstrap";
|
||||
import {HeaderBar} from "./navigation/header-bar/header-bar";
|
||||
import {Footer} from "./footer/footer";
|
||||
import "./style/index.scss";
|
||||
import {Login} from "../pages/login/login";
|
||||
|
||||
export const Landing: React.FC = () => {
|
||||
return (
|
||||
<Container>
|
||||
<HeaderBar/>
|
||||
<Switch>
|
||||
<Route path="/history">
|
||||
<History/>
|
||||
</Route>
|
||||
<Route path="/intro">
|
||||
<Intro/>
|
||||
</Route>
|
||||
<Route path="/login">
|
||||
<Login/>
|
||||
</Route>
|
||||
</Switch>
|
||||
<Footer/>
|
||||
</Container>);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
.header-nav {
|
||||
.nav-link {
|
||||
border-bottom: 2px solid transparent
|
||||
}
|
||||
|
||||
.nav-link.active {
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
import React from 'react'
|
||||
import {Navbar} from 'react-bootstrap';
|
||||
import {useSelector} from "react-redux";
|
||||
import {ApplicationState} from "../../../../../redux";
|
||||
import {NewUserNoteButton} from "../new-user-note-button";
|
||||
import {UserDropdown} from "../user-dropdown/user-dropdown";
|
||||
import {SignInButton} from "../sign-in-button";
|
||||
import {NewGuestNoteButton} from "../new-guest-note-button";
|
||||
import {LoginStatus} from "../../../../../redux/user/types";
|
||||
import {HeaderNavLink} from "../header-nav-link";
|
||||
import "./header-bar.scss";
|
||||
import {Trans, useTranslation} from "react-i18next";
|
||||
|
||||
const HeaderBar: React.FC = () => {
|
||||
useTranslation()
|
||||
const user = useSelector((state: ApplicationState) => state.user);
|
||||
|
||||
return (
|
||||
<Navbar className="justify-content-between">
|
||||
<div className="nav header-nav">
|
||||
<HeaderNavLink to="/intro">
|
||||
<Trans i18nKey="intro"/>
|
||||
</HeaderNavLink>
|
||||
<HeaderNavLink to="/history">
|
||||
<Trans i18nKey="history"/>
|
||||
</HeaderNavLink>
|
||||
</div>
|
||||
<div className="d-inline-flex">
|
||||
{user.status === LoginStatus.forbidden ?
|
||||
<>
|
||||
<span className={"mr-1"}>
|
||||
<NewGuestNoteButton/>
|
||||
</span>
|
||||
<SignInButton/>
|
||||
</>
|
||||
:
|
||||
<>
|
||||
<span className={"mr-1"}>
|
||||
<NewUserNoteButton/>
|
||||
</span>
|
||||
<UserDropdown/>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</Navbar>
|
||||
);
|
||||
}
|
||||
|
||||
export {HeaderBar}
|
||||
|
17
src/components/landing/layout/navigation/header-nav-link.tsx
Normal file
17
src/components/landing/layout/navigation/header-nav-link.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import {Nav} from "react-bootstrap";
|
||||
import {LinkContainer} from "react-router-bootstrap";
|
||||
import React from "react";
|
||||
|
||||
export interface HeaderNavLinkProps {
|
||||
to: string
|
||||
}
|
||||
|
||||
export const HeaderNavLink: React.FC<HeaderNavLinkProps> = (props) => {
|
||||
return (
|
||||
<Nav.Item>
|
||||
<LinkContainer to={props.to}>
|
||||
<Nav.Link className="text-light" href={props.to}>{props.children}</Nav.Link>
|
||||
</LinkContainer>
|
||||
</Nav.Item>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import React from "react";
|
||||
import {LinkContainer} from "react-router-bootstrap";
|
||||
import {Button} from "react-bootstrap";
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||
import {Trans, useTranslation} from "react-i18next";
|
||||
|
||||
export const NewGuestNoteButton: React.FC = () => {
|
||||
const {i18n} = useTranslation();
|
||||
return (
|
||||
<LinkContainer to={'/new'} title={i18n.t("newGuestNote")}>
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
className="d-inline-flex align-items-center">
|
||||
<FontAwesomeIcon icon="plus" className="mr-1"/>
|
||||
<span>
|
||||
<Trans i18nKey='newGuestNote'/>
|
||||
</span>
|
||||
</Button>
|
||||
</LinkContainer>)
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import {LinkContainer} from "react-router-bootstrap";
|
||||
import {Button} from "react-bootstrap";
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||
import React from "react";
|
||||
import {Trans, useTranslation} from "react-i18next";
|
||||
|
||||
export const NewUserNoteButton: React.FC = () => {
|
||||
const {i18n} = useTranslation()
|
||||
return (
|
||||
<LinkContainer to={'/new'} title={i18n.t("newNote")}>
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
className="d-inline-flex align-items-center">
|
||||
<FontAwesomeIcon icon="plus" className="mr-1"/>
|
||||
<span>
|
||||
<Trans i18nKey='newNote'/>
|
||||
</span>
|
||||
</Button>
|
||||
</LinkContainer>
|
||||
)
|
||||
}
|
19
src/components/landing/layout/navigation/sign-in-button.tsx
Normal file
19
src/components/landing/layout/navigation/sign-in-button.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import React from "react";
|
||||
import {Button} from "react-bootstrap";
|
||||
import {Trans, useTranslation} from "react-i18next";
|
||||
import {LinkContainer} from "react-router-bootstrap";
|
||||
|
||||
export const SignInButton: React.FC = () => {
|
||||
const {i18n} = useTranslation();
|
||||
|
||||
return (
|
||||
<LinkContainer to="/login" title={i18n.t("signIn")}>
|
||||
<Button
|
||||
variant="success"
|
||||
size="sm"
|
||||
>
|
||||
<Trans i18nKey="signIn"/>
|
||||
</Button>
|
||||
</LinkContainer>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
.user-avatar {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
import {Dropdown} from "react-bootstrap";
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||
import React from "react";
|
||||
import {useDispatch, useSelector} from "react-redux";
|
||||
import {ApplicationState} from "../../../../../redux";
|
||||
import {LinkContainer} from "react-router-bootstrap";
|
||||
import {clearUser} from "../../../../../redux/user/actions";
|
||||
import "./user-dropdown.scss";
|
||||
import {Trans} from "react-i18next";
|
||||
|
||||
export const UserDropdown: React.FC = () => {
|
||||
const user = useSelector((state: ApplicationState) => state.user);
|
||||
const dispatch = useDispatch()
|
||||
|
||||
return (
|
||||
<Dropdown alignRight>
|
||||
<Dropdown.Toggle size="sm" variant="dark" id="dropdown-basic">
|
||||
<div className='d-inline-flex align-items-baseline'>
|
||||
<img
|
||||
src={user.photo}
|
||||
className="user-avatar"
|
||||
alt={`Avatar of ${user.name}`}
|
||||
/><span>{user.name}</span>
|
||||
</div>
|
||||
</Dropdown.Toggle>
|
||||
|
||||
<Dropdown.Menu>
|
||||
<LinkContainer to={`/features`}>
|
||||
<Dropdown.Item>
|
||||
<FontAwesomeIcon icon="bolt"/>
|
||||
<Trans i18nKey="features"/>
|
||||
</Dropdown.Item>
|
||||
</LinkContainer>
|
||||
<LinkContainer to={`/me/export`}>
|
||||
<Dropdown.Item>
|
||||
<FontAwesomeIcon icon="cloud-download-alt"/>
|
||||
<Trans i18nKey="exportUserData"/>
|
||||
</Dropdown.Item>
|
||||
</LinkContainer>
|
||||
<Dropdown.Item href="#">
|
||||
<FontAwesomeIcon icon="trash"/>
|
||||
<Trans i18nKey="deleteUser"/>
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
onClick={() => {
|
||||
dispatch(clearUser());
|
||||
}}>
|
||||
<FontAwesomeIcon icon="sign-out-alt"/>
|
||||
<Trans i18nKey="signOut"/>
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>)
|
||||
};
|
398
src/components/landing/layout/style/cover.scss
Normal file
398
src/components/landing/layout/style/cover.scss
Normal file
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
* Globals
|
||||
*/
|
||||
|
||||
/* Links */
|
||||
|
||||
a,
|
||||
a:focus,
|
||||
a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
/* Custom default button */
|
||||
|
||||
.btn-default,
|
||||
.btn-default:hover,
|
||||
.btn-default:focus {
|
||||
color: #333;
|
||||
text-shadow: none;
|
||||
/* Prevent inheritence from `body` */
|
||||
background-color: #fff;
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
/*
|
||||
* Base structure
|
||||
*/
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
background-color: #333;
|
||||
}
|
||||
body {
|
||||
min-height: 100%;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-shadow: 0 1px 3px rgba(0, 0, 0, .5);
|
||||
}
|
||||
/* Extra markup and styles for table-esque vertical and horizontal centering */
|
||||
|
||||
.site-wrapper {
|
||||
padding: 10px;
|
||||
display: table;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
/* For at least Firefox */
|
||||
min-height: 100%;
|
||||
-webkit-box-shadow: inset 0 0 100px rgba(0, 0, 0, .5);
|
||||
box-shadow: inset 0 0 100px rgba(0, 0, 0, .5);
|
||||
}
|
||||
.site-wrapper-inner {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.cover-container {
|
||||
width: 100%;
|
||||
padding-top: 80px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
/* Padding for spacing */
|
||||
|
||||
.inner {
|
||||
padding: 10px;
|
||||
}
|
||||
/*
|
||||
* Header
|
||||
*/
|
||||
|
||||
.masthead {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.masthead-brand {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.masthead-nav {
|
||||
text-align: left;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.masthead-nav > li {
|
||||
display: inline-block;
|
||||
}
|
||||
.masthead-nav > li + li {
|
||||
margin-left: 20px;
|
||||
}
|
||||
.masthead-nav > li > a {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
/* IE8 proofing */
|
||||
color: rgba(255, 255, 255, .75);
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
.masthead-nav > li > a:hover,
|
||||
.masthead-nav > li > a:focus {
|
||||
background-color: transparent;
|
||||
border-bottom-color: #a9a9a9;
|
||||
border-bottom-color: rgba(255, 255, 255, .25);
|
||||
}
|
||||
.masthead-nav > .active > a,
|
||||
.masthead-nav > .active > a:hover,
|
||||
.masthead-nav > .active > a:focus {
|
||||
color: #fff;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.masthead-brand {
|
||||
float: left;
|
||||
}
|
||||
.masthead-nav {
|
||||
float: none;
|
||||
}
|
||||
.inner {
|
||||
padding: 30px 25px;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Cover
|
||||
*/
|
||||
|
||||
.cover {
|
||||
padding: 0 20px;
|
||||
}
|
||||
.cover .btn-lg {
|
||||
padding: 10px 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
/*
|
||||
* Footer
|
||||
*/
|
||||
|
||||
.mastfoot {
|
||||
color: #999;
|
||||
/* IE8 proofing */
|
||||
color: rgba(255, 255, 255, .5);
|
||||
}
|
||||
/*
|
||||
* Affix and center
|
||||
*/
|
||||
|
||||
@media (min-width: 768px) {
|
||||
/* Pull out the header and footer */
|
||||
.masthead {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100% !important;
|
||||
}
|
||||
.mastfoot {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
}
|
||||
/* Start the vertical centering */
|
||||
.site-wrapper-inner {
|
||||
vertical-align: middle;
|
||||
}
|
||||
/* Handle the widths */
|
||||
.masthead,
|
||||
.mastfoot,
|
||||
.cover-container {
|
||||
width: 100%;
|
||||
/* Must be percentage or pixels for horizontal alignment */
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.masthead,
|
||||
.mastfoot,
|
||||
.cover-container {
|
||||
width: 1000px;
|
||||
}
|
||||
}
|
||||
.section ul {
|
||||
list-style: none;
|
||||
}
|
||||
/* custom */
|
||||
|
||||
html,
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
input {
|
||||
color: black;
|
||||
}
|
||||
.mastfoot {
|
||||
position: relative;
|
||||
}
|
||||
.select2-container-multi .select2-choices .select2-search-field input {
|
||||
font-family: inherit;
|
||||
padding: 5px 12px;
|
||||
}
|
||||
.select2-container {
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
.list {
|
||||
width: 100%;
|
||||
padding-left: 0;
|
||||
display: -webkit-inline-flex;
|
||||
display: -moz-inline-flex;
|
||||
display: -ms-inline-flex;
|
||||
display: -o-inline-flex;
|
||||
display: inline-flex;
|
||||
-webkit-flex-direction: row;
|
||||
-moz-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-flex-flow: row wrap;
|
||||
-moz-flex-flow: row wrap;
|
||||
-ms-flex-flow: row wrap;
|
||||
flex-flow: row wrap;
|
||||
-webkit-justify-content: flex-start;
|
||||
-moz-justify-content: flex-start;
|
||||
-ms-justify-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.list {
|
||||
margin: 20px 0;
|
||||
}
|
||||
.list li {
|
||||
padding: 0 10px;
|
||||
}
|
||||
.list li * {
|
||||
word-break: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.list li a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.list li p {
|
||||
color: gray;
|
||||
}
|
||||
.list li .item {
|
||||
padding: 5px 25px;
|
||||
margin: 10px 0;
|
||||
background: white;
|
||||
border-radius: 5px;
|
||||
color: black;
|
||||
text-shadow: none;
|
||||
min-height: 134px;
|
||||
display: table;
|
||||
min-width: 100%;
|
||||
}
|
||||
.list li .item .content {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.list li .item .content .tags {
|
||||
line-height: 25px;
|
||||
}
|
||||
.list li .item .content .tags span {
|
||||
display: inline-block;
|
||||
line-height: 15px;
|
||||
}
|
||||
.form-inline {
|
||||
padding: 0 10px;
|
||||
}
|
||||
.sort.asc {
|
||||
text-decoration: overline;
|
||||
}
|
||||
.sort.desc {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.ui-avatar {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.ui-avatar.circle {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.ui-history-close {
|
||||
position: absolute;
|
||||
right: 14px;
|
||||
top: 15px;
|
||||
font-size: 16px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.ui-history-close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
.ui-history-pin {
|
||||
position: absolute;
|
||||
left: 14px;
|
||||
top: 15px;
|
||||
font-size: 16px;
|
||||
opacity: 0.2;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
-webkit-transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
.item:hover .ui-history-pin:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
.item .ui-history-pin.active {
|
||||
opacity: 1;
|
||||
color: #d43f3a;
|
||||
}
|
||||
.ui-or {
|
||||
margin: 5px;
|
||||
}
|
||||
.ui-use-tags {
|
||||
min-width: 172px;
|
||||
max-width: 344px;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
text-align: left;
|
||||
color: black;
|
||||
}
|
||||
.modal-body {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.btn-file {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.btn-file input[type=file] {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
font-size: 100px;
|
||||
text-align: right;
|
||||
filter: alpha(opacity=0);
|
||||
opacity: 0;
|
||||
outline: none;
|
||||
background: white;
|
||||
cursor: inherit;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.social-foot {
|
||||
line-height: 30px;
|
||||
}
|
||||
.social-foot > * {
|
||||
line-height: 20px;
|
||||
vertical-align: middle !important;
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
.btn-link, .btn-link:hover, .btn-link:focus, .btn-link:active {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.screenshot {
|
||||
margin: 30px auto;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
select {
|
||||
color: black;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
span.ui-or {
|
||||
display: block;
|
||||
}
|
||||
.ui-use-tags {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
/* for all pages should include this */
|
||||
body {
|
||||
font-smoothing: subpixel-antialiased !important;
|
||||
-webkit-font-smoothing: subpixel-antialiased !important;
|
||||
-moz-osx-font-smoothing: auto !important;
|
||||
text-shadow: 0 0 1em transparent, 1px 1px 1.2px rgba(0, 0, 0, 0.004);
|
||||
/*text-rendering: optimizeLegibility;*/
|
||||
-webkit-overflow-scrolling: touch;
|
||||
font-family: "Source Sans Pro", Helvetica, Arial, sans-serif;
|
||||
letter-spacing: 0.025em;
|
||||
}
|
||||
:focus, .focus {
|
||||
outline: none !important;
|
||||
}
|
||||
::-moz-focus-inner {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
/* manual fix for bootstrap issue 14040, there is an unnecessary padding-right on modal open */
|
||||
body.modal-open {
|
||||
overflow-y: auto;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
208
src/components/landing/layout/style/font-pack.scss
Normal file
208
src/components/landing/layout/style/font-pack.scss
Normal file
|
@ -0,0 +1,208 @@
|
|||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Code Pro';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Code Pro Light'), local('SourceCodePro-Light'), url('fonts/SourceCodePro-Light.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Code Pro';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Code Pro Light'), local('SourceCodePro-Light'), url('fonts/SourceCodePro-Light.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Code Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Code Pro'), local('SourceCodePro-Regular'), url('fonts/SourceCodePro-Regular.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Code Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Code Pro'), local('SourceCodePro-Regular'), url('fonts/SourceCodePro-Regular.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Code Pro';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: local('Source Code Pro Medium'), local('SourceCodePro-Medium'), url('fonts/SourceCodePro-Medium.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Code Pro';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: local('Source Code Pro Medium'), local('SourceCodePro-Medium'), url('fonts/SourceCodePro-Medium.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('fonts/SourceCodePro-Medium.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('fonts/SourceSansPro-Light.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('/src/components/indexnents/index/fonts/SourceSansPro-Light.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url('fonts/SourceSansPro-Regular.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url('fonts/SourceSansPro-Regular.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url('fonts/SourceSansPro-Regular.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), url('fonts/SourceSansPro-Semibold.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), url('fonts/SourceSansPro-Semibold.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), url('fonts/SourceSansPro-Semibold.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightIt'), url('fonts/SourceSansPro-LightItalic.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightIt'), url('fonts/SourceSansPro-LightItalic.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightIt'), url('fonts/SourceSansPro-LightItalic.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-It'), url('fonts/SourceSansPro-Italic.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-It'), url('fonts/SourceSansPro-Italic.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-It'), url('fonts/SourceSansPro-Italic.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold Italic'), local('SourceSansPro-SemiboldIt'), url('fonts/SourceSansPro-SemiboldItalic.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold Italic'), local('SourceSansPro-SemiboldIt'), url('fonts/SourceSansPro-SemiboldItalic.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro Semibold Italic'), local('SourceSansPro-SemiboldIt'), url('fonts/SourceSansPro-SemiboldItalic.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Serif Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Serif Pro'), local('SourceSerifPro-Regular'), url('fonts/SourceSerifPro-Regular.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Serif Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Serif Pro'), local('SourceSerifPro-Regular'), url('fonts/SourceSerifPro-Regular.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/components/landing/layout/style/fonts/SourceCodePro-Bold.eot
Normal file
BIN
src/components/landing/layout/style/fonts/SourceCodePro-Bold.eot
Normal file
Binary file not shown.
BIN
src/components/landing/layout/style/fonts/SourceCodePro-Bold.ttf
Normal file
BIN
src/components/landing/layout/style/fonts/SourceCodePro-Bold.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/components/landing/layout/style/fonts/SourceSansPro-Bold.eot
Normal file
BIN
src/components/landing/layout/style/fonts/SourceSansPro-Bold.eot
Normal file
Binary file not shown.
BIN
src/components/landing/layout/style/fonts/SourceSansPro-Bold.ttf
Normal file
BIN
src/components/landing/layout/style/fonts/SourceSansPro-Bold.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
23
src/components/landing/layout/style/index.scss
Normal file
23
src/components/landing/layout/style/index.scss
Normal file
|
@ -0,0 +1,23 @@
|
|||
@import "../../../../../node_modules/bootstrap/scss/bootstrap";
|
||||
@import "font-pack";
|
||||
//@import "cover.scss";
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
background-color: #333;
|
||||
}
|
||||
body {
|
||||
min-height: 100%;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
//text-shadow: 0 1px 3px rgba(0, 0, 0, .5);
|
||||
font-family: "Source Sans Pro", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
*:focus {
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
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}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue