diff options
Diffstat (limited to 'client/src')
22 files changed, 705 insertions, 0 deletions
diff --git a/client/src/admin/jsx/App.jsx b/client/src/admin/jsx/App.jsx new file mode 100644 index 0000000..c5be77c --- /dev/null +++ b/client/src/admin/jsx/App.jsx @@ -0,0 +1,36 @@ +import React, { useState, useEffect } from 'react'; +import ReactDOM from 'react-dom'; + +import "../scss/index.scss"; + +import texts from '../../common/data/texts.js'; +import TopBar from '../../common/jsx/TopBar.jsx'; +import Info from '../../common/jsx/Info.jsx'; +import MainScreen from './MainScreen.jsx'; + +const App = () => { + const [adminLang, setAdminLang] = useState('en'); + const [projects, setProjects] = useState([]); + const [info, setInfo] = useState(''); + const [hover, setHover] = useState(''); + const [view, setView] = useState('main'); + const [user, setUser] = useState(null); + const t = (key) => texts[adminLang][key] || texts['en'][key]; + + // useEffect(() => { + // setInfo('no-saved-websites') + // setHover(''); + // }, [user]); + + return ( + <div className="main"> + <TopBar lang={adminLang} setLang={setAdminLang} setHover={setHover} user={user} setUser={setUser} t={t} /> + <div className="main__content"> + { view === 'main' && <MainScreen projects={projects} t={t} setHover={setHover} /> } + </div> + <Info info={info} hover={hover} t={t} /> + </div> + ) +}; + +ReactDOM.render(<App />, document.getElementById('app')); diff --git a/client/src/admin/jsx/MainScreen.jsx b/client/src/admin/jsx/MainScreen.jsx new file mode 100644 index 0000000..ff28256 --- /dev/null +++ b/client/src/admin/jsx/MainScreen.jsx @@ -0,0 +1,25 @@ +import React, { Fragment } from 'react'; +import WithHover from '../../common/jsx/WithHover.jsx'; + +const MainScreen = ({ projects, t, setHover }) => ( + <div className="main-screen"> + <h1 className="main-screen__header">{ t('main-title') }</h1> + <div className="main-screen__list"> + { !projects.length && ( + <WithHover setHover={setHover} message="edit-current-project-hover"> + <p className="main-screen__item">{ t('edit-current-project') }</p> + </WithHover> + )} + { !projects.length && ( + <WithHover setHover={setHover} message="show-saved-projects-hover"> + <p className="main-screen__item">{ t('show-saved-projects') }</p> + </WithHover> + )} + <WithHover setHover={setHover} message="create-new-project-hover"> + <p className="main-screen__item">{ t('create-new-project') }</p> + </WithHover> + </div> + </div> +); + +export default MainScreen; diff --git a/client/src/admin/scss/_mainScreen.scss b/client/src/admin/scss/_mainScreen.scss new file mode 100644 index 0000000..4eec73a --- /dev/null +++ b/client/src/admin/scss/_mainScreen.scss @@ -0,0 +1,30 @@ +.main-screen { + text-align: center; + + &__header { + display: block; + margin-top: 10vh; + margin-bottom: 20vh; + font-size: 300%; + color: white; + text-align: center; + } + + &__list { + display: inline-block; + } + + &__item { + font-size: 175%; + color: white; + transition: color .3s; + cursor: pointer; + margin-top: 5vh; + margin-bottom: 5vh; + + &:hover { + color: $text-selected; + } + } + +} diff --git a/client/src/admin/scss/index.scss b/client/src/admin/scss/index.scss new file mode 100644 index 0000000..67553bb --- /dev/null +++ b/client/src/admin/scss/index.scss @@ -0,0 +1,8 @@ +@import '../../common/scss/reset'; +@import '../../common/scss/colors'; +@import '../../common/scss/globals'; +@import '../../common/scss/forms'; +@import '../../common/scss/main'; +@import '../../common/scss/info'; +@import '../../common/scss/topBar'; +@import 'mainScreen'; diff --git a/client/src/common/data/texts.js b/client/src/common/data/texts.js new file mode 100644 index 0000000..999460f --- /dev/null +++ b/client/src/common/data/texts.js @@ -0,0 +1,36 @@ +export default { + "en": { + "main-title": "Website Manager", + "login-to-admin": "Login to Admin Panel", + "login-info": "Put your user name and password, then click login button", + "login": "Login", + "user": "User name", + "password": "Password", + "no-saved-websites": "You don't have any saved projects, create a new one", + "create-new-project": "Create new project", + "create-new-project-hover": "Click to create new project", + "edit-current-project": "Edit current project", + "edit-current-project-hover": "Click to edit current active projecct", + "show-saved-projects": "Show saved projects", + "show-saved-projects-hover": "Click to show list of all saved projects", + "click-to-change-language": "Click to change language in the website manager", + "click-to-change-user": "Click to logout or change user password", + "logout": "Logout", + "click-to-logout": "Click to logout/change current user", + "user-settings": "User settings", + "click-to-change-user-settings": "Click to change user name, password or to completely remove current user", + }, + "de": { + "main-title": "Website Manager", + }, + "es": { + "main-title": "Website Manager", + }, + "pl": { + "main-title": "Website Manager", + "no-saved-websites": "Nie masz jeszcze żadnych zapisanych projektów, utwórz nowy", + "create-new-project": "Utwórz nowy projekt", + "edit-current-project": "Edytuj bieżący projekt", + "show-saved-projects": "Pokaż zapisane projekty", + }, +} diff --git a/client/src/common/jsx/Info.jsx b/client/src/common/jsx/Info.jsx new file mode 100644 index 0000000..00d04b3 --- /dev/null +++ b/client/src/common/jsx/Info.jsx @@ -0,0 +1,9 @@ +import React from 'react'; + +const Info = ({info, hover, t}) => ( + <p className="info"> + { hover ? t(hover) : t(info) } + </p> +); + +export default Info; diff --git a/client/src/common/jsx/LangSwitch.jsx b/client/src/common/jsx/LangSwitch.jsx new file mode 100644 index 0000000..eba1b27 --- /dev/null +++ b/client/src/common/jsx/LangSwitch.jsx @@ -0,0 +1,43 @@ +import React from 'react'; +import WithHover from './WithHover.jsx'; +import texts from '../data/texts.js'; + +const LangSwitch = ({ lang, setLang, setHover, opened, setOpened}) => { + + const handleSetLang = (key) => { + setLang(key); + setOpened(false); + }; + + return ( + <div className="lang-switch"> + <WithHover setHover={setHover} message="click-to-change-language"> + <span + className={`lang-switch__main-item${opened === 'lang' ? ' lang-switch__main-item--active' : ''}`} + onClick={() => setOpened(opened !== 'lang' ? 'lang' : false)} + > + {lang} + </span> + { + opened === 'lang' && ( + <div className="lang-switch__list"> + { + Object.keys(texts).map(key => key !== lang && ( + <span + className="lang-switch__item" + key={key} + onClick={() => handleSetLang(key)} + > + {key} + </span> + )) + } + </div> + ) + } + </WithHover> + </div> + ); +}; + +export default LangSwitch; diff --git a/client/src/common/jsx/TopBar.jsx b/client/src/common/jsx/TopBar.jsx new file mode 100644 index 0000000..6e5ad6a --- /dev/null +++ b/client/src/common/jsx/TopBar.jsx @@ -0,0 +1,38 @@ +import React, {useState} from 'react'; +import LangSwitch from './LangSwitch.jsx'; +import User from './User.jsx'; + +const TopBar = ({user, setUser, setHover, lang, setLang, t={t}}) => { + const [opened, setOpened] = useState(false); + + return ( + <div className="top-bar"> + { opened !== false && ( + <div + className="top-bar__fog" + onClick={() => setOpened(false)} + /> + )} + <LangSwitch + lang={lang} + setLang={setLang} + setHover={setHover} + opened={opened} + setOpened={setOpened} + /> + { user && ( + <User + user={user} + setUser={setUser} + setHover={setHover} + t={t} + opened={opened} + setOpened={setOpened} + /> + ) + } + </div> + ); +}; + +export default TopBar; diff --git a/client/src/common/jsx/User.jsx b/client/src/common/jsx/User.jsx new file mode 100644 index 0000000..8b05d44 --- /dev/null +++ b/client/src/common/jsx/User.jsx @@ -0,0 +1,38 @@ +import React from 'react'; +import WithHover from './WithHover.jsx'; + +const User = ({user, setUser, setHover, t, opened, setOpened}) => { + const handleLogout = () => { + setOpened(false); + setUser(null); + }; + const handleChangePass = () => { setOpened(false) }; + const handleRemoveUser = () => { setOpened(false) }; + + return ( + <div className="user"> + <WithHover setHover={setHover} message="click-to-change-user"> + <span + className={`user__main-item${opened === 'user' ? ' user__main-item--active' : ''}`} + onClick={() => setOpened(opened !== 'user' ? 'user' : false)} + > + {user} + </span> + { + opened === 'user' && ( + <div className="user__list" > + <WithHover setHover={setHover} message="click-to-logout"> + <span className="user__item" onClick={handleLogout}>{t('logout')}</span> + </WithHover> + <WithHover setHover={setHover} message="click-to-change-user-settings"> + <span className="user__item" onClick={handleChangePass}>{t('user-settings')}</span> + </WithHover> + </div> + ) + } + </WithHover> + </div> + ); +}; + +export default User; diff --git a/client/src/common/jsx/WithHover.jsx b/client/src/common/jsx/WithHover.jsx new file mode 100644 index 0000000..bb1a7f4 --- /dev/null +++ b/client/src/common/jsx/WithHover.jsx @@ -0,0 +1,13 @@ +import React from 'react'; + +const WithHover = ({ children, setHover, message, classes }) => ( + <div + onMouseEnter={()=>setHover(message)} + onMouseLeave={()=>setHover(null)} + className={classes} + > + {children} + </div> +); + +export default WithHover; diff --git a/client/src/common/scss/_colors.scss b/client/src/common/scss/_colors.scss new file mode 100644 index 0000000..2dd49a0 --- /dev/null +++ b/client/src/common/scss/_colors.scss @@ -0,0 +1,5 @@ +$background: #181818; +$text: #eee; +$text-highlighted: #fff; +$text-selected: orange; +$text-inactive: #aaa; diff --git a/client/src/common/scss/_forms.scss b/client/src/common/scss/_forms.scss new file mode 100644 index 0000000..b7ac0f4 --- /dev/null +++ b/client/src/common/scss/_forms.scss @@ -0,0 +1,52 @@ +// Text Input + +.text-input { + text-align: left; + margin-bottom: 1.5em; + transition: all .3s; + cursor: text; + + &:focus-within { + transform: scale(1.05,1.05); + } +} + +.text-input-label { + font-size: 1.25em; + width: 100%; + color: #aaa; + display:block; + transform:translateY(-1.75em); + transform-origin: 0 0; + transition: all .3s; + z-index: -1; + cursor: text; +} + +.text-input-field { + font-size: 1.5rem; + box-shadow: none; + background: $background; + color: $text-highlighted; + border-radius: 0; + border-color: #ccc; + border-style: none none solid none; + width: 100%; + transition: all .5s; + padding: 5px; + + &::placeholder { + color: transparent; + } + + &:focus { + box-shadow: none; + outline: none; + border-color: $text-selected; + } + + &:focus + .text-input-label, + &:not(:placeholder-shown) + .text-input-label { + transform: translateY(-3em) scale(0.8); + } +} diff --git a/client/src/common/scss/_globals.scss b/client/src/common/scss/_globals.scss new file mode 100644 index 0000000..f03ad86 --- /dev/null +++ b/client/src/common/scss/_globals.scss @@ -0,0 +1,12 @@ +html { + background: $background; +} + +* { + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: -moz-none; + -o-user-select: none; + user-select: none; +} + diff --git a/client/src/common/scss/_info.scss b/client/src/common/scss/_info.scss new file mode 100644 index 0000000..ac32949 --- /dev/null +++ b/client/src/common/scss/_info.scss @@ -0,0 +1,8 @@ +.info { + display: block; + color: #ddd; + flex-grow: 0; + text-align: center; + padding-bottom: 3vh; + padding-top: 3vh; +} diff --git a/client/src/common/scss/_main.scss b/client/src/common/scss/_main.scss new file mode 100644 index 0000000..e182f3c --- /dev/null +++ b/client/src/common/scss/_main.scss @@ -0,0 +1,16 @@ +.main { + display: flex; + flex-direction: column; + justify-content: space-between; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + + &__content { + flex-grow: 1; + display: flex; + flex-direction: column; + } +} diff --git a/client/src/common/scss/_reset.scss b/client/src/common/scss/_reset.scss new file mode 100755 index 0000000..2928cc4 --- /dev/null +++ b/client/src/common/scss/_reset.scss @@ -0,0 +1,52 @@ +* { + box-sizing: border-box; +} + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + +html{ + min-width: 320px; + background: white; +} + diff --git a/client/src/common/scss/_topBar.scss b/client/src/common/scss/_topBar.scss new file mode 100644 index 0000000..fb0e6a5 --- /dev/null +++ b/client/src/common/scss/_topBar.scss @@ -0,0 +1,114 @@ +@keyframes showTopMenu { + 0% {transform: translateY(100%) scale(0.8) ; opacity: 0;} + 80% {transform: translateY(100%) scale(1.1); opacity: 100%;} + 100% {transform: translateY(100%) scale(1); opacity: 100%;} +} + +.top-bar { + flex-grow: 0; + display: flex; + justify-content: end; + padding: 1em; + + + &__fog { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + } +} + +.user { + position: relative; + + &__list { + position: absolute; + display: block; + bottom: 0; + right: 0; + transform: translateY(100%); + background: #222; + animation: showTopMenu .3s; + } + + &__main-item { + color: white; + display: block; + padding: .5em; + white-space: nowrap; + transition: color .3s; + cursor: pointer; + + &--active { + background: #222; + color: yellow; + } + + &:hover { + color: yellow; + } + } + + &__item { + display: block; + color: white; + padding: .5em; + font-weight: normal; + transition: color .3s; + cursor: pointer; + white-space: nowrap; + text-align: right; + + &:hover { + color: yellow; + } + } +} + +.lang-switch { + display: inline-block; + position: relative; + + &__list { + position: absolute; + bottom: 0; + left: 0; + right: 0; + transform: translateY(100%); + background: #222; + animation: showTopMenu .3s; + } + + &__main-item { + transition: .3s color; + padding: .5em; + display: block; + color: white; + font-weight: normal; + cursor: pointer; + + &:hover { + color: yellow; + } + + &--active { + background: #222; + color: yellow; + } + } + + &__item { + padding: .5em; + display: block; + color: white; + font-weight: normal; + cursor: pointer; + transition: color .3s; + + &:hover { + color: yellow; + } + } +} diff --git a/client/src/login/data/texts.js b/client/src/login/data/texts.js new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/client/src/login/data/texts.js diff --git a/client/src/login/jsx/App.jsx b/client/src/login/jsx/App.jsx new file mode 100644 index 0000000..a0109dd --- /dev/null +++ b/client/src/login/jsx/App.jsx @@ -0,0 +1,39 @@ +import React, { useState } from 'react'; +import ReactDOM from 'react-dom'; + +import "../scss/index.scss"; + +import texts from '../../common/data/texts.js'; +import TopBar from '../../common/jsx/TopBar.jsx'; +import Info from '../../common/jsx/Info.jsx'; +import LoginPanel from './LoginPanel.jsx'; + +const App = () => { + const [lang, setLang] = useState('en'); + const [info, setInfo] = useState('login-info'); + const [hover, setHover] = useState(''); + const [user, setUser] = useState(null); + const t = (key) => texts[lang][key] || texts['en'][key]; + + return ( + <div className="main"> + <TopBar + lang={lang} + setLang={setLang} + setHover={setHover} + t={t} + /> + <LoginPanel + setUser={setUser} + t={t} + /> + <Info + info={info} + hover={hover} + t={t} + /> + </div> + ) +}; + +ReactDOM.render(<App />, document.getElementById('app')); diff --git a/client/src/login/jsx/LoginPanel.jsx b/client/src/login/jsx/LoginPanel.jsx new file mode 100644 index 0000000..296dc0e --- /dev/null +++ b/client/src/login/jsx/LoginPanel.jsx @@ -0,0 +1,80 @@ +import React, {useState, useEffect} from 'react'; + +const LoginPanel = ({setUser, t}) => { + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + const [active, setActive] = useState(false); + + useEffect(() => { + if (username.length > 4 && password.length > 4) { + setActive(true); + } else { + setActive(false); + } + }, [username, password]) + + const usernameValidation = (e) => { + const value = e.target.value; + const regex = /^[0-9a-zA-Z]+$/; + + if ((value.length < 20 && value.match(regex)) || value === "") { + setUsername(value); + } + }; + + const passwordValidation = (e) => { + e.target.value.length < 20 && setPassword(e.target.value); + }; + + const submit = (e) => { + e.preventDefault(); + if (username === 'admin' && password === 'admin') { + setUser('admin'); + } + } + + return ( + <div className="login-panel"> + <form className="login-panel__form" onSubmit={submit}> + <p className="login-panel__header"> + {t('login-to-admin')} + </p> + <div className="text-input"> + <input + onChange={usernameValidation} + placeholder={t('user')} + id="admin-user-name" + name="admin-user-name" + type="text" + className="text-input-field" + value={username} + /> + <label htmlFor="admin-user-name" className="text-input-label">{t('user')}</label> + </div> + <div className="text-input"> + <input + onChange={passwordValidation} + placeholder={t('password')} + id="admin-password" + name="admin-password" + type="password" + className="text-input-field" + value={password} + /> + <label htmlFor="admin-password" className="text-input-label"> + {t('password')} + </label> + </div> + <div> + <input + type="submit" + className={`login-panel__button${active ? ' active' : ''}`} + value={t('login')} + /> + </div> + </form> + </div> + ); +}; + +export default LoginPanel; diff --git a/client/src/login/scss/_loginPanel.scss b/client/src/login/scss/_loginPanel.scss new file mode 100644 index 0000000..8afb066 --- /dev/null +++ b/client/src/login/scss/_loginPanel.scss @@ -0,0 +1,43 @@ +.login-panel { + text-align: center; + + &__form { + display: inline-block; + } + + &__header { + color: white; + font-size: 2em; + margin-bottom: 4em; + } + + &__button { + display: inline-block; + color: $text-inactive; + background: $background; + font-size: 1.25em; + border-radius: 1em; + border: 2px solid $text-inactive; + padding: .5em 1.5em; + margin: 0 auto; + transition: .3s color, .3s background; + cursor: pointer; + + &:hover { + background: $text-inactive; + color: $background; + } + + &.active { + background: $background; + color: $text-selected; + border: 2px solid $text-selected; + + &:hover { + background: $text-selected; + color: $background; + } + } + } + +} diff --git a/client/src/login/scss/index.scss b/client/src/login/scss/index.scss new file mode 100644 index 0000000..6a7eb52 --- /dev/null +++ b/client/src/login/scss/index.scss @@ -0,0 +1,8 @@ +@import '../../common/scss/reset'; +@import '../../common/scss/colors'; +@import '../../common/scss/globals'; +@import '../../common/scss/forms'; +@import '../../common/scss/main'; +@import '../../common/scss/info'; +@import '../../common/scss/topBar'; +@import 'loginPanel'; |