responsive design
This commit is contained in:
parent
37ca3fd7e4
commit
7dd52656e8
|
@ -2,26 +2,19 @@ import {FC} from "react";
|
||||||
import {LogoHolder} from "./LogoHolder";
|
import {LogoHolder} from "./LogoHolder";
|
||||||
import {SidebarToggleButton} from "./SidebarToggleButton";
|
import {SidebarToggleButton} from "./SidebarToggleButton";
|
||||||
import {useLogosTheme} from "../context/ThemeProvider";
|
import {useLogosTheme} from "../context/ThemeProvider";
|
||||||
import {Stack} from "./design-system/Stack/Stack";
|
|
||||||
|
|
||||||
interface IProps{
|
interface IProps{
|
||||||
toggleSidebar: () => void;
|
className?: string;
|
||||||
|
onSidebarToggle: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Header: FC<IProps> = (props) => {
|
export const Header: FC<IProps> = ({className="", onSidebarToggle}) => {
|
||||||
const {toggleSidebar} = props;
|
|
||||||
const {toggleMode} = useLogosTheme();
|
const {toggleMode} = useLogosTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header>
|
<header className={className}>
|
||||||
<Stack justifyContent={"space-between"}
|
<SidebarToggleButton onClick={onSidebarToggle} />
|
||||||
>
|
<LogoHolder onClick={toggleMode} filePath={"/assets/logos-logo.svg"}/>
|
||||||
<SidebarToggleButton onClick={toggleSidebar}/>
|
|
||||||
<div style={{width: "30%"}}/>
|
|
||||||
<div style={{width: "50%"}}>
|
|
||||||
<LogoHolder onClick={toggleMode} filePath={"/assets/logos-logo.svg"}/>
|
|
||||||
</div>
|
|
||||||
</Stack>
|
|
||||||
</header>
|
</header>
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -9,7 +9,12 @@ export interface ILogosHolderProps{
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LogoHolder: FC<PropsWithChildren<ILogosHolderProps>> = ({onClick, filePath, alt, title, children}) => (
|
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/>
|
<LogoSvg/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
|
@ -1,10 +1,18 @@
|
||||||
import {FC, PropsWithChildren} from "react";
|
import {FC, PropsWithChildren, useEffect, useState} from "react";
|
||||||
import {INavigationItemProps} from "../types/data.types";
|
import {INavigationItemProps} from "../types/data.types";
|
||||||
import Link from "next/link";
|
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");
|
const sidebar: INavigationItemProps = require("../public/compiled/sidebar.tree.min.json");
|
||||||
|
|
||||||
interface ISidebarProps{
|
interface ISidebarProps{
|
||||||
|
className?: string;
|
||||||
|
onClose?: () => void;
|
||||||
|
onOpen?: () => void;
|
||||||
|
initialHide?: boolean;
|
||||||
|
hide: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IMenuProps{
|
interface IMenuProps{
|
||||||
|
@ -56,14 +64,33 @@ const Menu: FC<IMenuProps> = (props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Sidebar: FC<ISidebarProps> = (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 mainItems = sidebar.children.filter((c) => c.children.length===0)
|
||||||
const subItems = 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 (
|
return (
|
||||||
<nav className={`default-sidebar`}>
|
<div className={`${className} ${hideClass}`}>
|
||||||
<Menu items={[{...sidebar, title: "", children: mainItems}]}/>
|
<nav className={`sidebarNav`}>
|
||||||
<br/>
|
<div className={"sidebar-close-icon button"} onClick={onClose}>
|
||||||
<Menu items={subItems}/>
|
<CloseIcon/>
|
||||||
</nav>
|
</div>
|
||||||
|
<Menu items={[{...sidebar, title: "", children: mainItems}]}/>
|
||||||
|
<br/>
|
||||||
|
<Menu items={subItems}/>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import type {AppProps} from 'next/app'
|
import type {AppProps} from 'next/app'
|
||||||
import {PageComponent} from "../types/page";
|
import {PageComponent} from "../types/page";
|
||||||
import {LogosThemeProvider} from "../context/ThemeProvider";
|
import {LogosThemeProvider} from "../context/ThemeProvider";
|
||||||
|
import Head from 'next/head'
|
||||||
|
|
||||||
interface IProps extends AppProps{
|
interface IProps extends AppProps{
|
||||||
Component: PageComponent
|
Component: PageComponent
|
||||||
|
@ -13,6 +14,10 @@ function App({Component, pageProps}: IProps) {
|
||||||
const {children, ...rest} = pageProps;
|
const {children, ...rest} = pageProps;
|
||||||
return (
|
return (
|
||||||
<LogosThemeProvider>
|
<LogosThemeProvider>
|
||||||
|
<Head>
|
||||||
|
<title>Logos site builder</title>
|
||||||
|
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
|
||||||
|
</Head>
|
||||||
<Component {...rest}>{children}</Component>
|
<Component {...rest}>{children}</Component>
|
||||||
</LogosThemeProvider>
|
</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 {
|
*, :after, :before {
|
||||||
-webkit-box-sizing: border-box;
|
-webkit-box-sizing: border-box;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
body, body.dark{
|
html, body{
|
||||||
background: var(--dark-background-color);
|
|
||||||
color: var(--dark-text-color);
|
}
|
||||||
font-family: var(--fontFamily);
|
|
||||||
|
body{
|
||||||
|
background: var(--bg-color);
|
||||||
|
color: var(--txt-color);
|
||||||
|
font-family: var(--ff);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.light{
|
body.light{
|
||||||
background: var(--light-background-color);
|
--bg-color: var(--light-background-color);
|
||||||
color: var(--light-text-color);
|
--txt-color: var(--light-text-color);
|
||||||
font-family: var(--fontFamily);
|
--hl-color: var(--light-highlight-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
a, a:visited, a:hover,
|
a, a:visited, a:hover{
|
||||||
body.dark a, body.dark a:visited, body.dark a:hover{
|
color: var(--hl-color);
|
||||||
color: var(--dark-highlight-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body.light a, body.light a:visited, body.light a:hover{
|
svg, svg *{
|
||||||
color: var(--dark-highlight-color);
|
fill: var(--txt-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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"]{
|
input[type="text"]{
|
||||||
background: var(--dark-background-color);
|
background: var(--bg-color);
|
||||||
color: var(--dark-text-color);
|
color: var(--txt-color);
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.light input[type="text"]{
|
|
||||||
background: var(--light-background-color);
|
|
||||||
color: var(--light-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
::placeholder,
|
::placeholder,
|
||||||
:-ms-input-placeholder,
|
:-ms-input-placeholder,
|
||||||
::-ms-input-placeholder {
|
::-ms-input-placeholder {
|
||||||
color: var(--dark-text-color);
|
color: var(--txt-color);
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light ::placeholder,
|
|
||||||
body.light :-ms-input-placeholder,
|
|
||||||
body.light ::-ms-input-placeholder {
|
|
||||||
color: var(--light-text-color);
|
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,19 +56,10 @@ nav a,
|
||||||
nav a:visited,
|
nav a:visited,
|
||||||
nav a:hover{
|
nav a:hover{
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: var(--dark-text-color) !important;
|
color: var(--txt-color) !important;
|
||||||
text-transform: capitalize;
|
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{
|
.default-sidebar .sidebar-menu > li.level-0{
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
@ -88,9 +68,12 @@ body.light nav a:hover{
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*this part should be coming from the content but for now for sake of the look*/
|
/*this part should be coming from the content but for now for sake of the look*/
|
||||||
h1,h2,h3,h4,h5,h6{
|
h1,h2,h3,h4,h5,h6{
|
||||||
font-size: inherit !important;
|
font-size: inherit !important;
|
||||||
/*font-weight: normal;*/
|
/*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 {TTemplateProps} from "../../types/ui.types";
|
||||||
import {Sidebar} from "../../components/Sidebar";
|
import {Sidebar} from "../../components/Sidebar";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
import {IMarkdown} from "../../types/data.types";
|
import {IMarkdown} from "../../types/data.types";
|
||||||
import {Header} from "../../components/Header";
|
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 style from "./Style.module.css";
|
||||||
|
|
||||||
import {SearchInput} from "../../components/SearchInput";
|
|
||||||
|
|
||||||
interface IProps{
|
interface IProps{
|
||||||
markdown: IMarkdown<any>;
|
markdown: IMarkdown<any>;
|
||||||
}
|
}
|
||||||
|
@ -17,33 +15,46 @@ interface IProps{
|
||||||
export const DefaultTemplate_Markdown: FC<TTemplateProps<IProps>> = (props) => {
|
export const DefaultTemplate_Markdown: FC<TTemplateProps<IProps>> = (props) => {
|
||||||
const {append = false, markdown} = props;
|
const {append = false, markdown} = props;
|
||||||
const [sidebarHide, setSideBarHide] = useState(false);
|
const [sidebarHide, setSideBarHide] = useState(false);
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||||
|
|
||||||
|
const onSidebarOpen = () => {
|
||||||
|
setSidebarOpen(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSidebarClose = () => {
|
||||||
|
setSidebarOpen(false);
|
||||||
|
setSideBarHide(true)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.container}>
|
<div className={style.container}>
|
||||||
<Header toggleSidebar={() => setSideBarHide(!sidebarHide)}/>
|
<Header className={style.header} onSidebarToggle={() => setSideBarHide(!sidebarHide)}/>
|
||||||
{!append&&props.children}
|
<div className={style.banner}/>
|
||||||
<div className={style.banner}>
|
<div className={style.mainContainer}>
|
||||||
<Stack>
|
<div className={`${style.sidebarWrapper} ${style.col_1_4}`}>
|
||||||
<div className={style.col_1_4}/>
|
<Sidebar className={`${style.sidebar} ${style.sidebarDefault}`}
|
||||||
<div className={`${style.searchInput} ${style.col_2_4}`}>
|
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/>
|
<SearchInput/>
|
||||||
</div>
|
</div>
|
||||||
</Stack>
|
<div className={style.content}>
|
||||||
</div>
|
{!append&&props.children}
|
||||||
<Stack>
|
<ReactMarkdown>
|
||||||
<div className={`${style.sidebarWrapper} ${style.col_1_4}`}>
|
{markdown.content}
|
||||||
{
|
</ReactMarkdown>
|
||||||
!sidebarHide&&
|
{append&&props.children}
|
||||||
<Sidebar/>
|
</div>
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<main className={style.col_2_4}>
|
|
||||||
<ReactMarkdown>
|
|
||||||
{markdown.content}
|
|
||||||
</ReactMarkdown>
|
|
||||||
</main>
|
</main>
|
||||||
</Stack>
|
</div>
|
||||||
{append&&props.children}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -1,29 +1,44 @@
|
||||||
@value headerGapT: 300px;
|
@value headerGapT: 300px;
|
||||||
@value headerGapB: 4em;
|
@value headerGapB: 4em;
|
||||||
@value containerGapT: 2em;
|
@value containerGapT: 2em;
|
||||||
|
@value mainGapT: 3em;
|
||||||
@value mainGapB: 20em;
|
@value mainGapB: 20em;
|
||||||
|
@value pagePaddingT: containerGapT;
|
||||||
|
@value pagePaddingR: inherit;
|
||||||
|
@value pagePaddingB: inherit;
|
||||||
|
@value pagePaddingL: inherit;
|
||||||
|
|
||||||
.container{
|
.container{
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
margin: auto;
|
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;
|
position: fixed;
|
||||||
top: containerGapT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.banner{
|
.banner{
|
||||||
/*background: var(--dark-background-color);*/
|
|
||||||
position: sticky;
|
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
padding-bottom: headerGapB;
|
padding-bottom: headerGapB;
|
||||||
padding-top: headerGapT;
|
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;
|
padding-bottom: mainGapB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,13 +50,9 @@
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebarWrapper{
|
.searchInput{
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: calc(headerGapB + 1em);
|
top: containerGapT;
|
||||||
}
|
|
||||||
|
|
||||||
.headerGap{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchInput input{
|
.searchInput input{
|
||||||
|
@ -54,8 +65,90 @@
|
||||||
|
|
||||||
.container nav > ul{
|
.container nav > ul{
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container ul, .container li{
|
.container ul, .container li{
|
||||||
list-style: none;
|
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