diff --git a/index.d.ts b/index.d.ts index a449c44eb8abd4e1e9b0e0a6e1088e25ab30cbc6..9b5e6636c506f43ec26067c04532a76dfbe59747 100644 --- a/index.d.ts +++ b/index.d.ts @@ -56,9 +56,28 @@ interface LinkProps { } export function Link(props: LinkProps): JSX.Element; +interface DataImage { + src: string; +} +interface Image { + images: Array<DataImage>; + isLogo: boolean; + delay?: number; +} +export function Carousel(props: Image): JSX.Element; + interface SearchProps {} export function Search(props: SearchProps): JSX.Element; +interface Ilogo { + to?: string; + className?: string; + src?: string; + title: string; + image: any +} +export function Logo(props:Ilogo): JSX.Element; + interface Service { title: string; subtitle: string; @@ -83,4 +102,9 @@ interface HeroProps { */ export function Hero(props: HeroProps): JSX.Element; +interface MapProps { + idMap: number; +} +export function Map(props: MapProps): JSX.Element; + declare module "@onegeo/gatsby-theme-onegeo"; diff --git a/index.js b/index.js index b6c68578dd5828fa88c8ce68b94622d3b26bbd34..c9ef35913dc123a0bc40c7a3704a7431cf2d3e8b 100644 --- a/index.js +++ b/index.js @@ -10,6 +10,14 @@ export { default as Card } from "./src/components/core/Card"; export { default as Link } from "./src/components/core/Link"; export { default as Search } from "./src/components/core/Search"; export { default as Footer } from "./src/components/core/Footer"; +export { default as Map } from "./src/components/core/Map"; // Feature components export { default as Hero } from "./src/components/Hero"; + +//Carousel components +export { default as Carousel } from "./src/components/core/Carousel"; + +// Logo components +export { default as Logo } from "./src/components/core/Logo"; + diff --git a/package.json b/package.json index 81058b6950d82582f2a69688181f363ec41facf9..7935df1d2916bb8a7dc1aa7a4f6bacef0ba94c13 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "gatsby-source-graphql": "^4.12.1", "react-autosuggest": "^10.1.0", "react-instantsearch-dom": "^6.12.1", + "react-leaflet": "^3.2.5", "typesense-instantsearch-adapter": "^1.2.2" }, "devDependencies": { diff --git a/src/components/core/Carousel.tsx b/src/components/core/Carousel.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2b36018ffe9b635ff7e2d5e6b9043535bf1e5cbc --- /dev/null +++ b/src/components/core/Carousel.tsx @@ -0,0 +1,118 @@ +import React from "react"; + +interface DataImage { + src: string; +} + +interface Props { + images: Array<DataImage>; + isLogo: boolean; + delay?: number; +} + +const Carousel = (props: Props) => { + const { images, isLogo, delay } = props; + const [index, setIndex] = React.useState(1); + // const [leftAndRightDisabled, setLeftAndRightDisabled] = React.useState(false); + // const [stateSlides, setStateSlides] = React.useState<any[]>([]); + + const nbr_image: number = images.length; + + const updateIndex = (newIndex: number) => { + if (newIndex < 0) { + newIndex = nbr_image - 1; + } else if (newIndex >= nbr_image) { + newIndex = 0; + } + + setIndex(newIndex); + }; + + // React.useEffect(() => { + // const slidesWithClones = [...images]; + // slidesWithClones.unshift(slidesWithClones[slidesWithClones.length - 1]); + // slidesWithClones.push(slidesWithClones[1]); + // setStateSlides(slidesWithClones); + + // // ... + // }, []); + + React.useEffect(() => { + const interval = setInterval(() => { + if (delay != 0) { + updateIndex(index + 1); + } + }, delay); + + return () => { + if (interval) { + clearInterval(interval); + } + }; + }); + + return ( + <div className="block relative"> + <div + className={`carousel ${isLogo ? "w-[50%] ml-20" : "w-full"} truncate`} + > + <div + className={`whitespace-nowrap ${isLogo ? "w-[25%]" : "w-full"} `} + style={{ + transform: + isLogo ? + nbr_image > 4 + ? `translateX(-${index * 60 }%)` + : `translateX(0)` + : `translateX(-${index * 100}%)`, + transition: "transform 0.3s", + }} + > + {images.map((item: any, key: any) => { + return ( + <div + className={`carousel-item relative w-full inline-block`} + key={key} + > + {isLogo ? ( + <div className="flex justify-center items-center w-full"> + <img + src={item.src} + className="w-28 h-28 border border-gray-600 p-4" + /> + </div> + ) : ( + <img src={item.src} className="w-full h-[384px]" /> + )} + </div> + ); + })} + </div> + </div> + <div + className={`absolute flex justify-between pl-5 pr-5 ${ + isLogo ? "w-[62%]" : "w-full" + } ${isLogo ? "mt-[0%] top-9" : " mt-[0%] top-[47%]"} `} + > + <button + onClick={() => updateIndex(index - 1)} + className={`bg-[#5A5C68] rounded-3xl ${ + isLogo ? "w-5" : "w-10" + } h-10 text-white`} + > + â® + </button> + <button + onClick={() => updateIndex(index + 1)} + className={`bg-[#5A5C68] rounded-3xl ${ + isLogo ? "w-5" : "w-10" + } h-10 text-white`} + > + ⯠+ </button> + </div> + </div> + ); +}; + +export default Carousel; diff --git a/src/components/core/Logo.tsx b/src/components/core/Logo.tsx index 05478d6c35553a6bc762694f2e26be904e2032b8..ca5b33427345a2d44072f6a24f943964c67a2777 100644 --- a/src/components/core/Logo.tsx +++ b/src/components/core/Logo.tsx @@ -1,26 +1,32 @@ import React from "react"; import { Link } from "gatsby"; import { StaticImage } from "gatsby-plugin-image"; + // import logo from "../images/logo-egeo.png"; interface Props { to?: string; className?: string; src?: string; + title: string; + image: any } const Logo = (props: Props) => { - const { to = "#", className = "" } = props; + const { to = "#", className = "", title, image } = props; return ( - <Link to={to} className={className}> - <StaticImage - src="../images/logo-egeo.png" - alt="Logo" - height={40} - className="m-2" - /> - </Link> + <div className="flex justify-center flex-col items-center w-[150px]"> + <Link to={to} className={className}> + <img + src={image} + alt="Logo" + height={40} + className="my-2" + /> + </Link> + <div>{title}</div> + </div> ); }; diff --git a/src/components/core/Map.tsx b/src/components/core/Map.tsx new file mode 100644 index 0000000000000000000000000000000000000000..45078ed2ed1556f25225acde3ab08640fe835c1a --- /dev/null +++ b/src/components/core/Map.tsx @@ -0,0 +1,172 @@ +/* eslint-disable react-hooks/rules-of-hooks */ +import React, { useState, useEffect } from "react" +import { isArray } from "lodash" +import { + MapContainer, + LayersControl, + TileLayer, + WMSTileLayer, + GeoJSON, +} from "react-leaflet" +import "leaflet/dist/leaflet.css" + +interface Props { + idMap: number; +} + +const Map = (props: Props) => { + const projectUrl = process.env.PROJECT_URL as string + if (typeof window !== "undefined") { + let className = "z-40 h-full w-full" + + // Default id map (from mapstore) + const idMap = props.idMap + + // Default center, zoom + const center: number[] = [47.1, -1.25] + const zoom: number = 9 + const layers: any[] = [] + + // Get current map Object when ready (whenCreated) + const [map, setMap] = useState(null) + + // Init default map context + const [mapContext, setMapContext] = useState({ + center: { + x: center[1], + y: center[0], + }, + zoom: zoom, + layers: layers, + }) + + // Get Mapstore context + useEffect(() => { + fetch(projectUrl + "/geoportail/rest/geostore/data/" + idMap) + .then((response) => response.json()) + .then((resultData) => { + setMapContext(resultData.map) + // Update map view with context data + if (map) + // @ts-ignore + map.setView( + [resultData.map.center.y, resultData.map.center.x], + resultData.map.zoom + ) + }) + .catch((error) => { + console.log(error); + }) + }, [projectUrl, map, idMap]) + + return ( + <> + <MapContainer + center={[mapContext.center.y, mapContext.center.x]} + zoom={mapContext.zoom} + // @ts-ignore + whenCreated={setMap} + className={className} + // scrollWheelZoom={false} + > + <LayersControl> + { + // BACKGROUNDS + mapContext.layers + .filter((layer) => layer.group === "background") + .map((layer, key) => { + switch (layer.type) { + case "osm": + return ( + <LayersControl.BaseLayer + key={key} + checked={layer.visibility} + name={layer.title} + > + <TileLayer + attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' + url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + /> + </LayersControl.BaseLayer> + ) + case "wmts": + // URL for IGN WMTS services + // TODO: test for other WMTS + const url = + layer.url + + "?service=WMTS&request=GetTile&version=1.0.0&tilematrixset=PM&tilematrix={z}&tilecol={x}&tilerow={y}&layer=" + + layer.name + + "&format=" + + layer.format + + "&style=" + + layer.style + return ( + <LayersControl.BaseLayer + key={key} + checked={layer.visibility} + name={layer.title} + > + <TileLayer + url={url} + tileSize={256} + opacity={layer.opacity} + /> + </LayersControl.BaseLayer> + ) + } + }) + } + + { + // OVERLAYS + + // Load layers from context + mapContext.layers.map((layer, key) => { + if (isArray(layer.url)) return null + switch (layer.type) { + case "vector": + return ( + <LayersControl.Overlay + key={key} + checked={layer.visibility} + name={layer.name} + > + <GeoJSON + data={layer.features} + pathOptions={layer.style || ""} + /> + </LayersControl.Overlay> + ) + case "wfs": + break + case "wms": + return ( + <LayersControl.Overlay + key={key} + checked={layer.visibility} + name={layer.title} + > + <WMSTileLayer + layers={layer.name} + format={layer.format} + transparent={true} + url={layer.url} + styles={layer.style || ""} + opacity={layer.opacity} + /> + </LayersControl.Overlay> + ) + } + return null + }) + } + </LayersControl> + </MapContainer> + </> + ) + } + + return null +} + +export default Map diff --git a/src/pages-doc/doc/core/carousel.tsx b/src/pages-doc/doc/core/carousel.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a7404610257faad6c85abe995806ee4b82835cbc --- /dev/null +++ b/src/pages-doc/doc/core/carousel.tsx @@ -0,0 +1,74 @@ +import React from 'react' +import { Link } from "gatsby"; + +import { Content } from "@onegeo/gatsby-theme-onegeo"; +import { Carousel } from "@onegeo/gatsby-theme-onegeo"; + + +const carousel = () => { + const dataImage = [ + { + src: "https://placeimg.com/800/200/arch", + }, + { + src: "https://placeimg.com/800/200/arch", + }, + { + src: "https://placeimg.com/800/200/arch", + }, + { + src: "https://placeimg.com/800/200/arch", + }, + + ]; + return ( + <Content> + <div className="prose"> + <Link to="/doc/core">Retour</Link> + + <h1>Carousel</h1> + <h2>Props</h2> + <div className="mockup-code"> + <pre> + <code> + {` +interface DataImage { + src: string; + } + + interface Props { + images: Array<DataImage>; + isLogo: boolean; + delay?: number; + } + + const dataImage = [ + { + src: logo1, + }, + { + src: logo2, + }, + { + src: logo3, + }, + { + src: logo4, + }, + { + src: logo5, + }, +]; +`} + </code> + </pre> + </div> + + <h2>Example</h2> + </div> + <Carousel images = {dataImage} isLogo = {false} delay={3000}/> + </Content> + ) +} + +export default carousel diff --git a/src/pages-doc/doc/core/index.tsx b/src/pages-doc/doc/core/index.tsx index 532a3cd7b9ed98600022873c92b601197aa3b3c7..5b65485db64c4701e598d8728fb3ef92319b46a0 100644 --- a/src/pages-doc/doc/core/index.tsx +++ b/src/pages-doc/doc/core/index.tsx @@ -16,6 +16,13 @@ function index(): ReactElement { <Link to="/doc/core/hero">Hero</Link> <br></br> <Link to="/doc/core/footer">Footer</Link> + <br></br> + <Link to="/doc/core/carousel">Carousel</Link> + <br></br> + <Link to="/doc/core/map">Map</Link> + <br></br> + <Link to="/doc/core/logo">Logo</Link> + </div> </Content> ); diff --git a/src/pages-doc/doc/core/logo.tsx b/src/pages-doc/doc/core/logo.tsx new file mode 100644 index 0000000000000000000000000000000000000000..efabc0ca106c1b7bfdc1ea7a9fd3236c691bd4f9 --- /dev/null +++ b/src/pages-doc/doc/core/logo.tsx @@ -0,0 +1,38 @@ +import React from 'react' +import { Content } from "@onegeo/gatsby-theme-onegeo"; +import { Logo } from "@onegeo/gatsby-theme-onegeo"; +import { Link } from "gatsby"; +import image from "../../../images/logo-egeo.png" + +const logo = () => { + return ( + <Content> + <div className="prose"> + <Link to="/doc/core">Retour</Link> + + <h1>Logo</h1> + <h2>Props</h2> + <div className="mockup-code"> + <pre> + <code> + {`interface Props { + to?: string; + className?: string; + src?: string; + title: string; + image: any +}`} + </code> + </pre> + </div> + + <h2>Example</h2> + </div> + <div className="flex gap-6 m-4"> + <Logo title="My Logo" image={image} /> + </div> + </Content> + ) +} + +export default logo diff --git a/src/pages-doc/doc/core/map.tsx b/src/pages-doc/doc/core/map.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e3a20dbf62d6034fa5bcab2469175f165a8e00cf --- /dev/null +++ b/src/pages-doc/doc/core/map.tsx @@ -0,0 +1,37 @@ +import React, { ReactElement } from "react"; +import { Link } from "gatsby"; + +import { Content } from "@onegeo/gatsby-theme-onegeo"; +import { Map } from "@onegeo/gatsby-theme-onegeo"; + +function map(): ReactElement { + return ( + <Content> + <div className="prose"> + <Link to="/doc/core">Retour</Link> + + <h1>Map</h1> + <h2>Props</h2> + <div className="mockup-code"> + <pre> + <code> + {` +interface MapProps { + idMap: number; +}`} + </code> + </pre> + </div> + + <h2>Example</h2> + </div> + <div className="flex gap-6 m-4 h-96"> + <Map + idMap={109} + /> + </div> + </Content> + ); +} + +export default map;