responsive design
This commit is contained in:
parent
37ca3fd7e4
commit
7dd52656e8
|
@ -2,26 +2,19 @@ import {FC} from "react";
|
|||
import {LogoHolder} from "./LogoHolder";
|
||||
import {SidebarToggleButton} from "./SidebarToggleButton";
|
||||
import {useLogosTheme} from "../context/ThemeProvider";
|
||||
import {Stack} from "./design-system/Stack/Stack";
|
||||
|
||||
interface IProps{
|
||||
toggleSidebar: () => void;
|
||||
className?: string;
|
||||
onSidebarToggle: () => void;
|
||||
}
|
||||
|
||||
export const Header: FC<IProps> = (props) => {
|
||||
const {toggleSidebar} = props;
|
||||
export const Header: FC<IProps> = ({className="", onSidebarToggle}) => {
|
||||
const {toggleMode} = useLogosTheme();
|
||||
|
||||
return (
|
||||
<header>
|
||||
<Stack justifyContent={"space-between"}
|
||||
>
|
||||
<SidebarToggleButton onClick={toggleSidebar}/>
|
||||
<div style={{width: "30%"}}/>
|
||||
<div style={{width: "50%"}}>
|
||||
<LogoHolder onClick={toggleMode} filePath={"/assets/logos-logo.svg"}/>
|
||||
</div>
|
||||
</Stack>
|
||||
<header className={className}>
|
||||
<SidebarToggleButton onClick={onSidebarToggle} />
|
||||
<LogoHolder onClick={toggleMode} filePath={"/assets/logos-logo.svg"}/>
|
||||
</header>
|
||||
)
|
||||
}
|
|
@ -9,7 +9,12 @@ export interface ILogosHolderProps{
|
|||
}
|
||||
|
||||
export const LogoHolder: FC<PropsWithChildren<ILogosHolderProps>> = ({onClick, filePath, alt, title, children}) => (
|
||||
<div onClick={onClick} className={"logo-holder button"}>
|
||||
<div onClick={onClick}
|
||||
className={"logo-holder button"}
|
||||
style={{
|
||||
display: "inline-block"
|
||||
}}
|
||||
>
|
||||
<LogoSvg/>
|
||||
</div>
|
||||
)
|
|
@ -1,10 +1,18 @@
|
|||
import {FC, PropsWithChildren} from "react";
|
||||
import {FC, PropsWithChildren, useEffect, useState} from "react";
|
||||
import {INavigationItemProps} from "../types/data.types";
|
||||
import Link from "next/link";
|
||||
import {SidebarToggleButton} from "./SidebarToggleButton";
|
||||
import CloseIcon from "/public/assets/sidebar-icon-close.svg";
|
||||
import {useViewport} from "../utils/ui-utils";
|
||||
|
||||
const sidebar: INavigationItemProps = require("../public/compiled/sidebar.tree.min.json");
|
||||
|
||||
interface ISidebarProps{
|
||||
className?: string;
|
||||
onClose?: () => void;
|
||||
onOpen?: () => void;
|
||||
initialHide?: boolean;
|
||||
hide: boolean;
|
||||
}
|
||||
|
||||
interface IMenuProps{
|
||||
|
@ -56,14 +64,33 @@ const Menu: FC<IMenuProps> = (props) => {
|
|||
}
|
||||
|
||||
export const Sidebar: FC<ISidebarProps> = (props) => {
|
||||
const {className = "", onClose = ()=>{}, onOpen = () => {}, initialHide = false, hide} = props;
|
||||
const mainItems = sidebar.children.filter((c) => c.children.length===0)
|
||||
const subItems = sidebar.children.filter((c) => c.children.length!==0);
|
||||
const [firstTime, setFirstTime] = useState(false);
|
||||
|
||||
const isOpen = !((!firstTime&&initialHide) || hide);
|
||||
const hideClass = isOpen? "":"hide"
|
||||
|
||||
useEffect(() => {
|
||||
if(hide){
|
||||
setFirstTime(true);
|
||||
}
|
||||
if(isOpen){
|
||||
onOpen();
|
||||
}
|
||||
}, [hide, isOpen])
|
||||
|
||||
return (
|
||||
<nav className={`default-sidebar`}>
|
||||
<Menu items={[{...sidebar, title: "", children: mainItems}]}/>
|
||||
<br/>
|
||||
<Menu items={subItems}/>
|
||||
</nav>
|
||||
<div className={`${className} ${hideClass}`}>
|
||||
<nav className={`sidebarNav`}>
|
||||
<div className={"sidebar-close-icon button"} onClick={onClose}>
|
||||
<CloseIcon/>
|
||||
</div>
|
||||
<Menu items={[{...sidebar, title: "", children: mainItems}]}/>
|
||||
<br/>
|
||||
<Menu items={subItems}/>
|
||||
</nav>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import type {AppProps} from 'next/app'
|
||||
import {PageComponent} from "../types/page";
|
||||
import {LogosThemeProvider} from "../context/ThemeProvider";
|
||||
import Head from 'next/head'
|
||||
|
||||
interface IProps extends AppProps{
|
||||
Component: PageComponent
|
||||
|
@ -13,6 +14,10 @@ function App({Component, pageProps}: IProps) {
|
|||
const {children, ...rest} = pageProps;
|
||||
return (
|
||||
<LogosThemeProvider>
|
||||
<Head>
|
||||
<title>Logos site builder</title>
|
||||
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
|
||||
</Head>
|
||||
<Component {...rest}>{children}</Component>
|
||||
</LogosThemeProvider>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.34317 2.75729L11.2427 12.6568C11.6316 13.0457 12.268 13.0457 12.6569 12.6568C13.0458 12.2679 13.0458 11.6315 12.6569 11.2426L2.75738 1.34308C2.36847 0.954168 1.73208 0.954168 1.34317 1.34308C0.954258 1.73199 0.954258 2.36838 1.34317 2.75729Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.75741 12.6568L12.6569 2.75728C13.0458 2.36837 13.0458 1.73197 12.6569 1.34306C12.268 0.954155 11.6316 0.954155 11.2427 1.34306L1.3432 11.2426C0.95429 11.6315 0.95429 12.2679 1.3432 12.6568C1.73211 13.0457 2.3685 13.0457 2.75741 12.6568Z" fill="white"/>
|
||||
</svg>
|
After Width: | Height: | Size: 718 B |
|
@ -1,61 +1,50 @@
|
|||
:root{
|
||||
--bg-color: var(--dark-background-color);
|
||||
--txt-color: var(--dark-text-color);
|
||||
--hl-color: var(--dark-highlight-color);
|
||||
--ff: var(--fontFamily);
|
||||
}
|
||||
|
||||
*, :after, :before {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body, body.dark{
|
||||
background: var(--dark-background-color);
|
||||
color: var(--dark-text-color);
|
||||
font-family: var(--fontFamily);
|
||||
html, body{
|
||||
|
||||
}
|
||||
|
||||
body{
|
||||
background: var(--bg-color);
|
||||
color: var(--txt-color);
|
||||
font-family: var(--ff);
|
||||
}
|
||||
|
||||
body.light{
|
||||
background: var(--light-background-color);
|
||||
color: var(--light-text-color);
|
||||
font-family: var(--fontFamily);
|
||||
--bg-color: var(--light-background-color);
|
||||
--txt-color: var(--light-text-color);
|
||||
--hl-color: var(--light-highlight-color);
|
||||
}
|
||||
|
||||
a, a:visited, a:hover,
|
||||
body.dark a, body.dark a:visited, body.dark a:hover{
|
||||
color: var(--dark-highlight-color);
|
||||
a, a:visited, a:hover{
|
||||
color: var(--hl-color);
|
||||
}
|
||||
|
||||
body.light a, body.light a:visited, body.light a:hover{
|
||||
color: var(--dark-highlight-color);
|
||||
}
|
||||
|
||||
svg, svg *,
|
||||
body.dark svg, body.dark svg *{
|
||||
fill: var(--dark-text-color);
|
||||
}
|
||||
|
||||
body.light svg, body.light svg *{
|
||||
fill: var(--light-text-color);
|
||||
svg, svg *{
|
||||
fill: var(--txt-color);
|
||||
}
|
||||
|
||||
input[type="text"]{
|
||||
background: var(--dark-background-color);
|
||||
color: var(--dark-text-color);
|
||||
background: var(--bg-color);
|
||||
color: var(--txt-color);
|
||||
padding: 0.5em;
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
body.light input[type="text"]{
|
||||
background: var(--light-background-color);
|
||||
color: var(--light-text-color);
|
||||
}
|
||||
|
||||
::placeholder,
|
||||
:-ms-input-placeholder,
|
||||
::-ms-input-placeholder {
|
||||
color: var(--dark-text-color);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
body.light ::placeholder,
|
||||
body.light :-ms-input-placeholder,
|
||||
body.light ::-ms-input-placeholder {
|
||||
color: var(--light-text-color);
|
||||
color: var(--txt-color);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
@ -67,19 +56,10 @@ nav a,
|
|||
nav a:visited,
|
||||
nav a:hover{
|
||||
text-decoration: none;
|
||||
color: var(--dark-text-color) !important;
|
||||
color: var(--txt-color) !important;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
body.light nav a,
|
||||
body.light nav a:visited,
|
||||
body.light nav a:hover{
|
||||
text-decoration: none;
|
||||
color: var(--light-text-color) !important;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
|
||||
.default-sidebar .sidebar-menu > li.level-0{
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
@ -88,9 +68,12 @@ body.light nav a:hover{
|
|||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
||||
/*this part should be coming from the content but for now for sake of the look*/
|
||||
h1,h2,h3,h4,h5,h6{
|
||||
font-size: inherit !important;
|
||||
/*font-weight: normal;*/
|
||||
}
|
||||
|
||||
pre{
|
||||
overflow-x: auto;
|
||||
}
|
|
@ -1,15 +1,13 @@
|
|||
import {FC, useState} from "react";
|
||||
import {FC, useEffect, useState} from "react";
|
||||
import {TTemplateProps} from "../../types/ui.types";
|
||||
import {Sidebar} from "../../components/Sidebar";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import {IMarkdown} from "../../types/data.types";
|
||||
import {Header} from "../../components/Header";
|
||||
import {Stack} from "../../components/design-system/Stack/Stack";
|
||||
import {SearchInput} from "../../components/SearchInput";
|
||||
|
||||
import style from "./Style.module.css";
|
||||
|
||||
import {SearchInput} from "../../components/SearchInput";
|
||||
|
||||
interface IProps{
|
||||
markdown: IMarkdown<any>;
|
||||
}
|
||||
|
@ -17,33 +15,46 @@ interface IProps{
|
|||
export const DefaultTemplate_Markdown: FC<TTemplateProps<IProps>> = (props) => {
|
||||
const {append = false, markdown} = props;
|
||||
const [sidebarHide, setSideBarHide] = useState(false);
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
const onSidebarOpen = () => {
|
||||
setSidebarOpen(true);
|
||||
}
|
||||
|
||||
const onSidebarClose = () => {
|
||||
setSidebarOpen(false);
|
||||
setSideBarHide(true)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={style.container}>
|
||||
<Header toggleSidebar={() => setSideBarHide(!sidebarHide)}/>
|
||||
{!append&&props.children}
|
||||
<div className={style.banner}>
|
||||
<Stack>
|
||||
<div className={style.col_1_4}/>
|
||||
<div className={`${style.searchInput} ${style.col_2_4}`}>
|
||||
<Header className={style.header} onSidebarToggle={() => setSideBarHide(!sidebarHide)}/>
|
||||
<div className={style.banner}/>
|
||||
<div className={style.mainContainer}>
|
||||
<div className={`${style.sidebarWrapper} ${style.col_1_4}`}>
|
||||
<Sidebar className={`${style.sidebar} ${style.sidebarDefault}`}
|
||||
hide={sidebarHide}
|
||||
/>
|
||||
<Sidebar className={`${style.sidebar} ${style.sidebarNarrow}`}
|
||||
hide={sidebarHide}
|
||||
initialHide={true}
|
||||
onOpen={onSidebarOpen}
|
||||
onClose={onSidebarClose}
|
||||
/>
|
||||
</div>
|
||||
<main className={`${style.col_2_4}`}>
|
||||
<div className={`${style.searchInput} ${sidebarOpen? style.withOpenSidebar: ""}`}>
|
||||
<SearchInput/>
|
||||
</div>
|
||||
</Stack>
|
||||
</div>
|
||||
<Stack>
|
||||
<div className={`${style.sidebarWrapper} ${style.col_1_4}`}>
|
||||
{
|
||||
!sidebarHide&&
|
||||
<Sidebar/>
|
||||
}
|
||||
</div>
|
||||
<main className={style.col_2_4}>
|
||||
<ReactMarkdown>
|
||||
{markdown.content}
|
||||
</ReactMarkdown>
|
||||
<div className={style.content}>
|
||||
{!append&&props.children}
|
||||
<ReactMarkdown>
|
||||
{markdown.content}
|
||||
</ReactMarkdown>
|
||||
{append&&props.children}
|
||||
</div>
|
||||
</main>
|
||||
</Stack>
|
||||
{append&&props.children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,29 +1,44 @@
|
|||
@value headerGapT: 300px;
|
||||
@value headerGapB: 4em;
|
||||
@value containerGapT: 2em;
|
||||
@value mainGapT: 3em;
|
||||
@value mainGapB: 20em;
|
||||
@value pagePaddingT: containerGapT;
|
||||
@value pagePaddingR: inherit;
|
||||
@value pagePaddingB: inherit;
|
||||
@value pagePaddingL: inherit;
|
||||
|
||||
.container{
|
||||
max-width: 1200px;
|
||||
margin: auto;
|
||||
padding-top: containerGapT;
|
||||
padding-top: pagePaddingT;
|
||||
padding-bottom: pagePaddingB;
|
||||
padding-right: pagePaddingR;
|
||||
padding-left: pagePaddingL;
|
||||
}
|
||||
|
||||
.container :global(.sidebar-toggle-button){
|
||||
.mainContainer{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.header{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header :global(.sidebar-toggle-button){
|
||||
position: fixed;
|
||||
top: containerGapT;
|
||||
}
|
||||
|
||||
.banner{
|
||||
/*background: var(--dark-background-color);*/
|
||||
position: sticky;
|
||||
z-index: 9999;
|
||||
padding-bottom: headerGapB;
|
||||
padding-top: headerGapT;
|
||||
top: calc(calc(-1 * headerGapT) + containerGapT)
|
||||
top: calc(calc(-1 * headerGapT) + containerGapT);
|
||||
}
|
||||
|
||||
.container main{
|
||||
.container main .content{
|
||||
padding-top: mainGapT;
|
||||
padding-bottom: mainGapB;
|
||||
}
|
||||
|
||||
|
@ -35,13 +50,9 @@
|
|||
width: 50%;
|
||||
}
|
||||
|
||||
.sidebarWrapper{
|
||||
.searchInput{
|
||||
position: sticky;
|
||||
top: calc(headerGapB + 1em);
|
||||
}
|
||||
|
||||
.headerGap{
|
||||
|
||||
top: containerGapT;
|
||||
}
|
||||
|
||||
.searchInput input{
|
||||
|
@ -54,8 +65,90 @@
|
|||
|
||||
.container nav > ul{
|
||||
padding-left: 0;
|
||||
padding-top: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.container ul, .container li{
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/*SIDEBAR*/
|
||||
.sidebarWrapper{
|
||||
padding-top: calc(mainGapT - 1em)
|
||||
}
|
||||
.sidebar{
|
||||
position: sticky;
|
||||
top: calc(headerGapB + 3em);
|
||||
padding-top: mainGapT;
|
||||
}
|
||||
|
||||
.sidebar:global(.hide) nav{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebarDefault{
|
||||
}
|
||||
|
||||
.sidebarNarrow{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar :global(.sidebar-close-icon){
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width:600px) {
|
||||
@value pagePaddingT: 6em;
|
||||
@value pagePaddingR: 4em;
|
||||
@value pagePaddingB: 3em;
|
||||
@value pagePaddingL: 4em;
|
||||
|
||||
@value headerGapT: 100px;
|
||||
@value headerGapB: 4em;
|
||||
|
||||
.sidebarDefault{
|
||||
display: none;
|
||||
}
|
||||
.sidebarNarrow{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.searchInput.withOpenSidebar{
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.sidebar :global(.sidebar-close-icon){
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: pagePaddingT;
|
||||
transform: translate(9px, 10px);
|
||||
}
|
||||
|
||||
|
||||
.sidebar nav{
|
||||
position: fixed;
|
||||
background: var(--bg-color);
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
padding-top: calc(pagePaddingT + headerGapT);
|
||||
padding-bottom: pagePaddingB;
|
||||
padding-right: pagePaddingR;
|
||||
padding-left: pagePaddingL;
|
||||
}
|
||||
|
||||
.sidebar :global(.sidebar-toggle-button){
|
||||
z-index: 999999999;
|
||||
}
|
||||
|
||||
.searchInput{
|
||||
/*z-index: -1;*/
|
||||
}
|
||||
|
||||
.col_1_4, .col_2_4{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
import {useEffect, useState} from "react";
|
||||
|
||||
type TBox = {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export const useWindowDimensions = () => {
|
||||
//default SSR
|
||||
const [state, setState] = useState<TBox>({width: 1200, height: 800});
|
||||
|
||||
const onResize = () => {
|
||||
setState({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
onResize();
|
||||
window.addEventListener("resize", onResize);
|
||||
return () => window.removeEventListener("resize", onResize);
|
||||
}, []);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
interface IViewportState{
|
||||
isNarrow: boolean;
|
||||
}
|
||||
|
||||
export const useViewport = (): IViewportState => {
|
||||
const {width} = useWindowDimensions();
|
||||
return {
|
||||
isNarrow: width <= 600
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue