fix: hide search in mobile version

master
gman 2 years ago
parent 84f7187375
commit 684392e85b

@ -9,10 +9,6 @@ import { CustomFonts } from './CustomFonts';
import { KartaPage } from "./KartaPage"; import { KartaPage } from "./KartaPage";
import { Landing } from "./Landing"; import { Landing } from "./Landing";
import { Article } from "./Article"; import { Article } from "./Article";
import { HeaderSimple } from "./Header";
import { FooterLinks } from "./Footer";
import headerLinks from "./assets/header.json";
import footerLinks from "./assets/footer.json";
const router = createBrowserRouter([ const router = createBrowserRouter([
{ {
@ -42,9 +38,7 @@ function App() {
}}> }}>
<CustomFonts /> <CustomFonts />
<Box pos={"absolute"} w={"100%"} top={0}> <Box pos={"absolute"} w={"100%"} top={0}>
<HeaderSimple links={headerLinks.links} />
<RouterProvider router={router} /> <RouterProvider router={router} />
<FooterLinks data={footerLinks.data} />
</Box> </Box>
</MantineProvider> </MantineProvider>
); );

@ -1,11 +1,23 @@
import { Title, Container, rem, createStyles, TypographyStylesProvider, Image } from '@mantine/core'; import {
import { Carousel } from '@mantine/carousel'; Title,
import { useLoaderData } from 'react-router-dom'; Container,
import Markdown from 'react-markdown'; rem,
createStyles,
TypographyStylesProvider,
Image,
} from "@mantine/core";
import { Carousel } from "@mantine/carousel";
import { useLoaderData } from "react-router-dom";
import Markdown from "react-markdown";
import { HeaderSimple } from "./Header";
import { FooterLinks } from "./Footer";
import headerLinks from "./assets/header.json";
import footerLinks from "./assets/footer.json";
const useStyles = createStyles((theme) => ({ const useStyles = createStyles((theme) => ({
content: { content: {
padding: rem(30) padding: rem(30),
}, },
title: { title: {
@ -13,41 +25,55 @@ const useStyles = createStyles((theme) => ({
lineHeight: 1.2, lineHeight: 1.2,
fontWeight: 900, fontWeight: 900,
paddingBottom: rem(20), paddingBottom: rem(20),
[theme.fn.smallerThan('xs')]: { [theme.fn.smallerThan("xs")]: {
fontSize: rem(28), fontSize: rem(28),
}, },
} },
})); }));
export function Article() { export function Article() {
const articleData = useLoaderData(); const articleData = useLoaderData();
const { classes } = useStyles(); const { classes } = useStyles();
const article = articleData.data[0].attributes const article = articleData.data[0].attributes;
// console.log(articleData) // console.log(articleData)
const generateCarousel = () => { const generateCarousel = () => {
if (articleData.data[0].attributes.carousel.data) { if (articleData.data[0].attributes.carousel.data) {
return ( return (
<Carousel slideSize="70%" mih={200} mah={500} slideGap="md" loop> <Carousel slideSize="70%" mih={200} mah={500} slideGap="md" loop>
{articleData.data[0].attributes.carousel.data.map(image => <Carousel.Slide key={image.attributes.url}><Image fit='fill' mih={200} mah={500} mx="auto" radius="md" src={`https://strapi.litmusmap.ru${image.attributes.url}`} alt="Random image" /></Carousel.Slide>)} {articleData.data[0].attributes.carousel.data.map((image) => (
<Carousel.Slide key={image.attributes.url}>
<Image
fit="fill"
mih={200}
mah={500}
mx="auto"
radius="md"
src={`https://strapi.litmusmap.ru${image.attributes.url}`}
alt="Random image"
/>
</Carousel.Slide>
))}
</Carousel> </Carousel>
) );
} }
} };
return ( return (
<Container className={classes.content}> <>
<Title order={1} className={classes.title}> <HeaderSimple links={headerLinks.links} />
{article.title} <Container className={classes.content}>
</Title> <Title order={1} className={classes.title}>
<TypographyStylesProvider sx={{ '@media (prefers-color-scheme: dark)': { color: "#C1C2C5" } }}> {article.title}
<Markdown>{article.content}</Markdown> </Title>
</TypographyStylesProvider> <TypographyStylesProvider
{generateCarousel()} sx={{ "@media (prefers-color-scheme: dark)": { color: "#C1C2C5" } }}
</Container> >
<Markdown>{article.content}</Markdown>
</TypographyStylesProvider>
{generateCarousel()}
</Container>
<FooterLinks data={footerLinks.data} />
</>
); );
} }

@ -8,7 +8,7 @@ import {
rem, rem,
Image, Image,
Menu, Menu,
Dialog, Paper,
Stack, Stack,
} from "@mantine/core"; } from "@mantine/core";
import { IconExternalLink } from "@tabler/icons-react"; import { IconExternalLink } from "@tabler/icons-react";
@ -35,7 +35,7 @@ const useStyles = createStyles((theme) => ({
}, },
}, },
warning: { mobilemenu: {
[theme.fn.largerThan("md")]: { [theme.fn.largerThan("md")]: {
display: "none", display: "none",
}, },
@ -79,8 +79,8 @@ interface HeaderSimpleProps {
links: { link: string; label: string }[]; links: { link: string; label: string }[];
} }
export function HeaderSimple({ links }: HeaderSimpleProps) { export function HeaderSimple({ links, openedMenuKarta, menuactionskarta }: HeaderSimpleProps) {
const [openedMenu, menuactions] = useDisclosure(false); const [openedMenu, menuactions] = menuactionskarta ? [openedMenuKarta, menuactionskarta] : useDisclosure(false);
const [active, setActive] = useState(""); const [active, setActive] = useState("");
const { classes, cx } = useStyles(); const { classes, cx } = useStyles();
@ -106,81 +106,9 @@ export function HeaderSimple({ links }: HeaderSimpleProps) {
return ( return (
<Header height={60}> <Header height={60}>
<Container className={classes.header}> <Container className={classes.header}>
{/* <Title order={3}><Anchor href='/' inherit={true} color='black' underline={false}>Литературные музеи России</Anchor></Title> */}
{/* <MantineLogo size={28} /> */}
<Image maw={150} src={logo} component="a" href="/" /> <Image maw={150} src={logo} component="a" href="/" />
{/* Menu for mobile */}
<Dialog
opened={openedMenu}
withCloseButton={false}
onClose={menuactions.close}
size="xs"
radius="md"
position={{ top: 70, right: 20 }}
className={classes.warning}
>
<Stack spacing={5} className={classes.linksmobile}>
<Menu shadow="md" width={200}>
<Menu.Target>
<a
key="Авторы"
href="#authors"
className={cx(classes.link, {
[classes.linkActive]: active === "#authors",
})}
onClick={(e) => {
e.preventDefault();
// setActive("#authors");
}}
>
Авторы
</a>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item
rightSection={
<IconExternalLink
style={{ width: rem(14), height: rem(14) }}
/>
}
component="a"
href="https://bigenc.ru/c/ostrovskii-aleksandr-nikolaevich-c697e2"
target="_blank"
>
Островский
</Menu.Item>
<Menu.Item
rightSection={
<IconExternalLink
style={{ width: rem(14), height: rem(14) }}
/>
}
component="a"
href="https://bigenc.ru/c/prishvin-mikhail-mikhailovich-893107"
target="_blank"
>
Пришвин
</Menu.Item>
<Menu.Item
rightSection={
<IconExternalLink
style={{ width: rem(14), height: rem(14) }}
/>
}
component="a"
href="https://bigenc.ru/c/briusov-valerii-iakovlevich-fc6a35"
target="_blank"
>
Брюсов
</Menu.Item>
</Menu.Dropdown>
</Menu>
{items}
</Stack>
</Dialog>
{/* Menu for pc */} {/* Menu for pc */}
<Group spacing={5} className={classes.links}> <Group spacing={5} className={classes.links}>
@ -250,6 +178,81 @@ export function HeaderSimple({ links }: HeaderSimpleProps) {
size="sm" size="sm"
/> />
</Container> </Container>
{/* Menu for mobile */}
<Paper
display={!openedMenu && 'none'}
radius={0}
style={{
position: "absolute",
top: 60,
left: 0,
right: 0,
opacity: "95%",
padding: "10px 0 10px 1rem",
zIndex: 10
}}
className={classes.mobilemenu}
>
<Group spacing={5} className={classes.linksmobile}>
<Menu shadow="md" width={200}>
<Menu.Target>
<a
key="Авторы"
href="#authors"
className={cx(classes.link, {
[classes.linkActive]: active === "#authors",
})}
onClick={(e) => {
e.preventDefault();
// setActive("#authors");
}}
>
Авторы
</a>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item
rightSection={
<IconExternalLink
style={{ width: rem(14), height: rem(14) }}
/>
}
component="a"
href="https://bigenc.ru/c/ostrovskii-aleksandr-nikolaevich-c697e2"
target="_blank"
>
Островский
</Menu.Item>
<Menu.Item
rightSection={
<IconExternalLink
style={{ width: rem(14), height: rem(14) }}
/>
}
component="a"
href="https://bigenc.ru/c/prishvin-mikhail-mikhailovich-893107"
target="_blank"
>
Пришвин
</Menu.Item>
<Menu.Item
rightSection={
<IconExternalLink
style={{ width: rem(14), height: rem(14) }}
/>
}
component="a"
href="https://bigenc.ru/c/briusov-valerii-iakovlevich-fc6a35"
target="_blank"
>
Брюсов
</Menu.Item>
</Menu.Dropdown>
</Menu>
{items}
</Group>
</Paper>
</Header> </Header>
); );
} }

@ -1,4 +1,9 @@
import { Paper, Flex, ScrollArea, Autocomplete, Title } from "@mantine/core"; import { Paper, Flex, ScrollArea, Autocomplete, Title } from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { HeaderSimple } from "./Header";
import { FooterLinks } from "./Footer";
import headerLinks from "./assets/header.json";
import footerLinks from "./assets/footer.json";
import { ArticleCardVertical } from "./ArticleCard"; import { ArticleCardVertical } from "./ArticleCard";
import { ArticleCardMobile } from "./ArticleCardMobile"; import { ArticleCardMobile } from "./ArticleCardMobile";
import Map, { import Map, {
@ -18,7 +23,6 @@ import plus from "./assets/plus.png";
import minus from "./assets/minus.png"; import minus from "./assets/minus.png";
import pin from "./assets/pin.png"; import pin from "./assets/pin.png";
export function KartaPage() { export function KartaPage() {
const mapRef = useRef(null); const mapRef = useRef(null);
const [initial, setInitial] = useState(null); const [initial, setInitial] = useState(null);
@ -27,6 +31,8 @@ export function KartaPage() {
const [selected, setSelected] = useState(-1); const [selected, setSelected] = useState(-1);
const [cursor, setCursor] = useState("grab"); const [cursor, setCursor] = useState("grab");
const [popupInfo, setPopupInfo] = useState(null); const [popupInfo, setPopupInfo] = useState(null);
const [openedMenu, menuactions] = useDisclosure(false);
const host = "https://strapi.litmusmap.ru"; const host = "https://strapi.litmusmap.ru";
@ -37,11 +43,12 @@ export function KartaPage() {
pinImage.onload = () => mapRef.current.addImage("pin-marker", pinImage); pinImage.onload = () => mapRef.current.addImage("pin-marker", pinImage);
const icons = initial ? ["prishvin", "ostrovskiy", "brusov"] : []; const icons = initial ? ["prishvin", "ostrovskiy", "brusov"] : [];
icons.map(i => { icons.map((i) => {
const iconImage = new Image(); const iconImage = new Image();
iconImage.src = `./markers/${i}.png` iconImage.src = `./markers/${i}.png`;
iconImage.onload = () => mapRef.current.addImage(`${i}-marker`, iconImage); iconImage.onload = () =>
}) mapRef.current.addImage(`${i}-marker`, iconImage);
});
}; };
// Load articles // Load articles
@ -49,7 +56,7 @@ export function KartaPage() {
fetch(`${host}/api/articles?populate=*`) fetch(`${host}/api/articles?populate=*`)
.then((r) => r.json()) .then((r) => r.json())
.then((d) => { .then((d) => {
console.log(d.data) console.log(d.data);
setInitial(d.data); setInitial(d.data);
setArticles(d.data); setArticles(d.data);
}); });
@ -138,279 +145,292 @@ export function KartaPage() {
}; };
return ( return (
<div style={{ position: "relative" }}> <>
<Map <HeaderSimple links={headerLinks.links} openedMenuKarta={openedMenu} menuactionskarta={menuactions}/>
ref={mapRef} <div style={{ position: "relative" }}>
initialViewState={{ <Map
longitude: 35, ref={mapRef}
latitude: 60, initialViewState={{
zoom: 4, longitude: 35,
}} latitude: 60,
minZoom={3.5} zoom: 4,
maxZoom={16} }}
maxBounds={[ minZoom={3.5}
[-20, 35], maxZoom={16}
[200, 80], maxBounds={[
]} [-20, 35],
style={{ [200, 80],
height: "90vh", ]}
}} style={{
cursor={cursor} height: "90vh",
mapStyle={mapstyle} }}
interactiveLayerIds={["points-layer"]} cursor={cursor}
onClick={(e) => { mapStyle={mapstyle}
// console.log(e.features); interactiveLayerIds={["points-layer"]}
if (e.features[0]) { onClick={(e) => {
setSelected(e.features[0].properties.id); // console.log(e.features);
if (mapRef.current.getZoom() < 14) { if (e.features[0]) {
mapRef.current.flyTo({ setSelected(e.features[0].properties.id);
center: e.features[0].geometry.coordinates, if (mapRef.current.getZoom() < 14) {
zoom: mapRef.current.getZoom() + 6, mapRef.current.flyTo({
}); center: e.features[0].geometry.coordinates,
zoom: mapRef.current.getZoom() + 6,
});
} else {
setPopupInfo({
longitude: e.features[0].geometry.coordinates[0],
latitude: e.features[0].geometry.coordinates[1],
id: e.features[0].properties.id,
});
}
} else { } else {
setPopupInfo({ setSelected(-1);
longitude: e.features[0].geometry.coordinates[0],
latitude: e.features[0].geometry.coordinates[1],
id: e.features[0].properties.id,
});
} }
} else { }}
setSelected(-1); onMouseEnter={() => setCursor("pointer")}
} onMouseLeave={() => setCursor("grab")}
}} onLoad={handleMapLoad}
onMouseEnter={() => setCursor("pointer")}
onMouseLeave={() => setCursor("grab")}
onLoad={handleMapLoad}
>
<Source
id="points"
type="vector"
tiles={[`${host}/tiles/{z}/{x}/{y}.pbf`]}
maxzoom={10}
> >
{popupInfo && ( <Source
<Popup id="points"
key={popupInfo.id} type="vector"
longitude={popupInfo.longitude} tiles={[`${host}/tiles/{z}/{x}/{y}.pbf`]}
latitude={popupInfo.latitude} maxzoom={10}
anchor="top" >
closeButton={false} {popupInfo && (
onClose={() => setPopupInfo(null)} <Popup
> key={popupInfo.id}
<a href={`/article/${popupInfo.id}`}>подробнее</a> longitude={popupInfo.longitude}
</Popup> latitude={popupInfo.latitude}
)} anchor="top"
<Layer closeButton={false}
id="points-layer" onClose={() => setPopupInfo(null)}
type="circle" >
source-layer="layer" <a href={`/article/${popupInfo.id}`}>подробнее</a>
filter={ </Popup>
articles === null || articles.length == 0 )}
? false <Layer
: ["in", "id", ...articles.map((a) => a.id)] id="points-layer"
} type="circle"
paint={{ source-layer="layer"
"circle-color": [ filter={
"match", articles === null || articles.length == 0
["get", "id"], ? false
selected, : ["in", "id", ...articles.map((a) => a.id)]
"#e66a5a", }
"#F2994A", paint={{
], "circle-color": [
"circle-radius": ["step", ["zoom"], 8, 7, 20, 12, 40, 14, 60], "match",
"circle-opacity": ["step", ["zoom"], 0.8, 7, 0], ["get", "id"],
}} selected,
/> "#e66a5a",
<Layer "#F2994A",
id="icons-layer" ],
type="symbol" "circle-radius": ["step", ["zoom"], 8, 7, 20, 12, 40, 14, 60],
source-layer="layer" "circle-opacity": ["step", ["zoom"], 0.8, 7, 0],
filter={ }}
articles === null || articles.length == 0 />
? false <Layer
: ["in", "id", ...articles.map((a) => a.id)] id="icons-layer"
} type="symbol"
layout={{ source-layer="layer"
"icon-image": "pin-marker", filter={
"icon-size": ["interpolate", ["linear"], ["zoom"], 7, 0.5, 12, 1], articles === null || articles.length == 0
}} ? false
minzoom={7} : ["in", "id", ...articles.map((a) => a.id)]
maxzoom={12} }
/> layout={{
<Layer "icon-image": "pin-marker",
id="portret-layer" "icon-size": [
type="symbol" "interpolate",
source-layer="layer" ["linear"],
filter={ ["zoom"],
articles === null || articles.length == 0 7,
? false 0.5,
: ["in", "id", ...articles.map((a) => a.id)] 12,
} 1,
layout={{ ],
"icon-image": [ }}
"match", minzoom={7}
["get", "id"], maxzoom={12}
6, />
"ostrovskiy-marker", <Layer
7, id="portret-layer"
"brusov-marker", type="symbol"
1, source-layer="layer"
"prishvin-marker", filter={
"pin-marker", articles === null || articles.length == 0
], ? false
"icon-size": [ : ["in", "id", ...articles.map((a) => a.id)]
"interpolate", }
["linear"], layout={{
["zoom"], "icon-image": [
12, "match",
0.05, ["get", "id"],
14, 6,
0.1, "ostrovskiy-marker",
], 7,
"brusov-marker",
1,
"prishvin-marker",
"pin-marker",
],
"icon-size": [
"interpolate",
["linear"],
["zoom"],
12,
0.05,
14,
0.1,
],
}}
minzoom={12}
/>
</Source>
<ScaleControl position="bottom-right" />
<ZoomControl bottom="35px" right="4px" />
<GeolocateControl
showAccuracyCircle={false}
position="bottom-right"
style={{
marginBottom: "55px",
marginRight: "14px",
background: "none",
boxShadow: "none",
}} }}
minzoom={12}
/> />
</Source> </Map>
<ScaleControl position="bottom-right" />
<ZoomControl bottom="35px" right="4px" /> {/* Search mobile */}
<GeolocateControl <Paper
showAccuracyCircle={false} shadow={"md"}
position="bottom-right" radius={0}
display={!openedMenu && 'none'}
style={{ style={{
marginBottom: "55px", position: "absolute",
marginRight: "14px", top: 0,
background: "none", left: 0,
boxShadow: "none", right: 0,
height: "340px",
opacity: "95%",
padding: "55px 0 1rem 1rem"
}} }}
/> sx={{
</Map> "@media (min-width: 60em)": {
display: "none",
{/* Search mobile */} },
<Paper }}
shadow={"md"} >
radius={0} <Autocomplete
style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
height: "300px",
opacity: "95%",
padding: "1rem 0 1rem 1rem",
}}
sx={{
"@media (min-width: 60em)": {
display: "none",
},
}}
>
<Autocomplete
mr={20}
mb={10}
placeholder="Поиск"
limit={2}
value={search}
onChange={setSearch}
data={[]}
/>
<ScrollArea h={"225px"} type="auto">
<Flex
// mih={50}
gap="xs"
justify="flex-start"
align="start"
direction="column"
wrap="wrap"
mr={20} mr={20}
> mb={10}
{articles !== null && placeholder="Поиск"
articles.length > 0 && limit={2}
articles.map((article) => ( value={search}
<ArticleCardMobile onChange={setSearch}
key={article.id} data={[]}
id={article.id} />
image={ <ScrollArea h={"225px"} type="auto">
article.attributes.cover.data !== null <Flex
? host + article.attributes.cover.data.attributes.url // mih={50}
: "" gap="xs"
} justify="flex-start"
category="музеи" align="start"
title={article.attributes.title} direction="column"
address={article.attributes.address} wrap="wrap"
longitude={article.attributes.longitude} mr={20}
latitude={article.attributes.latitude} >
selected={selected} {articles !== null &&
clickAddressAction={handleAddressClick} articles.length > 0 &&
/> articles.map((article) => (
))} <ArticleCardMobile
</Flex> key={article.id}
</ScrollArea> id={article.id}
</Paper> image={
article.attributes.cover.data !== null
? host + article.attributes.cover.data.attributes.url
: ""
}
category="музеи"
title={article.attributes.title}
address={article.attributes.address}
longitude={article.attributes.longitude}
latitude={article.attributes.latitude}
selected={selected}
clickAddressAction={handleAddressClick}
/>
))}
</Flex>
</ScrollArea>
</Paper>
{/* Search pc */} {/* Search pc */}
<Paper <Paper
shadow={"md"} shadow={"md"}
withBorder withBorder
style={{ style={{
position: "absolute", position: "absolute",
top: "1rem", top: "1rem",
left: "1rem", left: "1rem",
width: "36rem", width: "36rem",
height: "83vh", height: "83vh",
opacity: "95%", opacity: "95%",
padding: "1rem 0 1rem 1rem", padding: "1rem 0 1rem 1rem",
}} }}
sx={{ sx={{
"@media (max-width: 60em)": { "@media (max-width: 60em)": {
display: "none", display: "none",
}, },
}} }}
> >
<Title order={3} mb={10}> <Title order={3} mb={10}>
Музеи Музеи
</Title> </Title>
<Autocomplete <Autocomplete
mr={20}
mb={30}
placeholder="Поиск"
limit={2}
value={search}
onChange={setSearch}
data={[]}
/>
<ScrollArea h={"67vh"} type="auto">
<Flex
mih={50}
gap="md"
justify="flex-start"
align="start"
direction="column"
wrap="wrap"
mr={20} mr={20}
> mb={30}
{articles !== null && placeholder="Поиск"
articles.length > 0 && limit={2}
articles.map((article) => ( value={search}
<ArticleCardVertical onChange={setSearch}
key={article.id} data={[]}
id={article.id} />
image={ <ScrollArea h={"67vh"} type="auto">
article.attributes.cover.data !== null <Flex
? host + article.attributes.cover.data.attributes.url mih={50}
: "" gap="md"
} justify="flex-start"
category="музеи" align="start"
title={article.attributes.title} direction="column"
address={article.attributes.address} wrap="wrap"
longitude={article.attributes.longitude} mr={20}
latitude={article.attributes.latitude} >
selected={selected} {articles !== null &&
clickAddressAction={handleAddressClick} articles.length > 0 &&
/> articles.map((article) => (
))} <ArticleCardVertical
</Flex> key={article.id}
</ScrollArea> id={article.id}
</Paper> image={
</div> article.attributes.cover.data !== null
? host + article.attributes.cover.data.attributes.url
: ""
}
category="музеи"
title={article.attributes.title}
address={article.attributes.address}
longitude={article.attributes.longitude}
latitude={article.attributes.latitude}
selected={selected}
clickAddressAction={handleAddressClick}
/>
))}
</Flex>
</ScrollArea>
</Paper>
</div>
<FooterLinks data={footerLinks.data} />
</>
); );
} }

@ -6,6 +6,11 @@ import {
TypographyStylesProvider, TypographyStylesProvider,
} from "@mantine/core"; } from "@mantine/core";
import { HeaderSimple } from "./Header";
import { FooterLinks } from "./Footer";
import headerLinks from "./assets/header.json";
import footerLinks from "./assets/footer.json";
const useStyles = createStyles((theme) => ({ const useStyles = createStyles((theme) => ({
content: { content: {
padding: rem(30), padding: rem(30),
@ -31,6 +36,8 @@ export function Landing() {
const { classes } = useStyles(); const { classes } = useStyles();
return ( return (
<>
<HeaderSimple links={headerLinks.links} />
<Container className={classes.content}> <Container className={classes.content}>
<Title order={1} className={classes.title}> <Title order={1} className={classes.title}>
О проекте О проекте
@ -98,5 +105,8 @@ export function Landing() {
</p> </p>
</TypographyStylesProvider> </TypographyStylesProvider>
</Container> </Container>
<FooterLinks data={footerLinks.data} />
</>
); );
} }

Loading…
Cancel
Save