PSSM Pictures Gallery
@ -1,10 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { BrowserRouter as Router, Route, Link, Switch, Routes } from "react-router-dom";
|
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
|
||||||
|
|
||||||
import Container from "react-bootstrap/Container";
|
import Container from "react-bootstrap/Container";
|
||||||
import Nav from "react-bootstrap/Nav";
|
import Nav from "react-bootstrap/Nav";
|
||||||
import Navbar from "react-bootstrap/Navbar";
|
import Navbar from "react-bootstrap/Navbar";
|
||||||
import NavDropdown from "react-bootstrap/NavDropdown";
|
|
||||||
import Home from "../../Pages/Home";
|
import Home from "../../Pages/Home";
|
||||||
import About from "../../Pages/About";
|
import About from "../../Pages/About";
|
||||||
import ControlInAfrica from "../../Pages/ControlInAfrica";
|
import ControlInAfrica from "../../Pages/ControlInAfrica";
|
||||||
@ -14,16 +13,17 @@ const NavBarSalw = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Router>
|
<Router>
|
||||||
<Navbar expand="lg" className="bg-body-tertiary">
|
<Navbar expand="lg" className="bg-body-tertiary nav-bar">
|
||||||
<Container>
|
<Container fluid className="ps-5">
|
||||||
<Navbar.Brand href="#home">SALW Guide</Navbar.Brand>
|
<Navbar.Brand className="nav-bar-title" href="#home">SALW Guide |</Navbar.Brand>
|
||||||
|
|
||||||
<Navbar.Toggle aria-controls="basic-navbar-nav" />
|
<Navbar.Toggle aria-controls="basic-navbar-nav" />
|
||||||
<Navbar.Collapse id="basic-navbar-nav">
|
<Navbar.Collapse id="basic-navbar-nav">
|
||||||
<Nav className="me-auto">
|
<Nav className="me-auto">
|
||||||
<Nav.Link href="home">Home</Nav.Link>
|
<Nav.Link className="nav-bar-item" href="home">Home</Nav.Link>
|
||||||
<Nav.Link href="ControlInAfrica">SALW Control in Africa</Nav.Link>
|
<Nav.Link className="nav-bar-item" href="ControlInAfrica">SALW Control in Africa</Nav.Link>
|
||||||
<Nav.Link href="pssm">PSSM</Nav.Link>
|
<Nav.Link className="nav-bar-item" href="pssm">PSSM</Nav.Link>
|
||||||
<Nav.Link href="about">About</Nav.Link>
|
<Nav.Link className="nav-bar-item" href="about">About</Nav.Link>
|
||||||
</Nav>
|
</Nav>
|
||||||
</Navbar.Collapse>
|
</Navbar.Collapse>
|
||||||
</Container>
|
</Container>
|
||||||
|
@ -2,7 +2,6 @@ import React, { useState } from "react";
|
|||||||
import Card_ from "../../UI/Card_/Card_";
|
import Card_ from "../../UI/Card_/Card_";
|
||||||
import DOMPurify from "dompurify";
|
import DOMPurify from "dompurify";
|
||||||
import parse from "html-react-parser";
|
import parse from "html-react-parser";
|
||||||
import TruncateContent from "../../Helpers/TruncateContent/TruncateContent";
|
|
||||||
import Collapse from "react-bootstrap/Collapse";
|
import Collapse from "react-bootstrap/Collapse";
|
||||||
|
|
||||||
const Blurb = () => {
|
const Blurb = () => {
|
||||||
@ -30,14 +29,14 @@ const Blurb = () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card_ className="p-3">
|
<Card_ className="blurb p-3">
|
||||||
<MainText footnotes={footnotes} />
|
<MainText footnotes={footnotes} />
|
||||||
</Card_>
|
</Card_>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const MainText = ({ footnotes }) => {
|
const MainText = ({ footnotes }) => {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(true);
|
||||||
const [isHidden, setIsHidden] = useState(true);
|
const [isHidden, setIsHidden] = useState(true);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -157,14 +156,17 @@ const MainText = ({ footnotes }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
<a
|
{/* <a
|
||||||
href="#"
|
href="#"
|
||||||
onClick={() => {setOpen(!open); setIsHidden(!isHidden);}}
|
onClick={() => {
|
||||||
|
setOpen(!open);
|
||||||
|
setIsHidden(!isHidden);
|
||||||
|
}}
|
||||||
aria-controls="example-collapse-text"
|
aria-controls="example-collapse-text"
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
>
|
>
|
||||||
{isHidden ? "Read more" : "Read less"}
|
{isHidden ? "Read more" : "Read less"}
|
||||||
</a>
|
</a> */}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
53
src/Components/Layout/PSSM/ImageGallery.jsx
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import images from "./ImportImages";
|
||||||
|
import Card_ from "../../UI/Card_/Card_";
|
||||||
|
|
||||||
|
const ImageGallery = () => {
|
||||||
|
const [selectedImage, setSelectedImage] = useState(null);
|
||||||
|
|
||||||
|
const handleThumbnailClick = (image) => {
|
||||||
|
setSelectedImage(image);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCloseModal = () => {
|
||||||
|
setSelectedImage(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card_ className="mt-3 p-3">
|
||||||
|
<div className="image-gallery">
|
||||||
|
{Object.keys(images).map((key, index) => (
|
||||||
|
<img
|
||||||
|
key={index}
|
||||||
|
src={images[key]}
|
||||||
|
alt={key}
|
||||||
|
className="thumbnail"
|
||||||
|
onClick={() => handleThumbnailClick(images[key])}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{selectedImage && (
|
||||||
|
<div className="modal" onClick={handleCloseModal}>
|
||||||
|
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
|
||||||
|
<span className="close" onClick={handleCloseModal}>
|
||||||
|
×
|
||||||
|
</span>
|
||||||
|
<img
|
||||||
|
src={selectedImage}
|
||||||
|
alt="Full Size"
|
||||||
|
className="full-size-image"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="mt-3">
|
||||||
|
<p>
|
||||||
|
Pictures have been taken by ©Nikhil Achary, ©IPSTC/Kenya, ©MSAG AUT,
|
||||||
|
and ©Hans Lampalzer (BLMV).{" "}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card_>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ImageGallery;
|
10
src/Components/Layout/PSSM/ImpactStories.jsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Card_ from '../../UI/Card_/Card_'
|
||||||
|
const ImpactStories = (props) => {
|
||||||
|
const {className} = props;
|
||||||
|
return (
|
||||||
|
<Card_ className={className}>ImpactStories</Card_>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ImpactStories
|
12
src/Components/Layout/PSSM/ImportImages.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// src/importImages.js
|
||||||
|
function importAll(r) {
|
||||||
|
let images = {};
|
||||||
|
r.keys().map((item, index) => {
|
||||||
|
images[item.replace('./', '')] = r(item);
|
||||||
|
});
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
const images = importAll(require.context('../../../img/pssm', false, /\.(png|jpe?g|svg)$/));
|
||||||
|
|
||||||
|
export default images;
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect, createRef } from "react";
|
||||||
|
|
||||||
import { MapContainer, GeoJSON, useMap } from "react-leaflet";
|
import { MapContainer, GeoJSON, useMap } from "react-leaflet";
|
||||||
import L from "leaflet";
|
import L from "leaflet";
|
||||||
@ -16,7 +16,7 @@ const CustomZoomControl = React.memo(() => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const zoomControl = L.control.zoom({
|
const zoomControl = L.control.zoom({
|
||||||
position: 'topright' // Change the position to bottom right
|
position: "topright", // Change the position to bottom right
|
||||||
});
|
});
|
||||||
map.addControl(zoomControl);
|
map.addControl(zoomControl);
|
||||||
|
|
||||||
@ -33,6 +33,8 @@ class PSSM extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
this.mapRef = createRef(); // Create a ref to store the MapContainer instance
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
africaCountries: null,
|
africaCountries: null,
|
||||||
countriesNames: [],
|
countriesNames: [],
|
||||||
@ -93,6 +95,22 @@ class PSSM extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
resetMap = () => {
|
||||||
|
if (this.mapRef.current) {
|
||||||
|
this.mapRef.current.setView(this.state.center, this.state.zoom); // Set the center and zoom to initial values
|
||||||
|
}
|
||||||
|
};
|
||||||
|
zoomIn = () => {
|
||||||
|
if (this.mapRef.current) {
|
||||||
|
this.mapRef.current.setZoom(this.mapRef.current.getZoom() + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
zoomOut = () => {
|
||||||
|
if (this.mapRef.current) {
|
||||||
|
this.mapRef.current.setZoom(this.mapRef.current.getZoom() - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMouseClick = (e) => {
|
onMouseClick = (e) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedCountriesFilter: [],
|
selectedCountriesFilter: [],
|
||||||
@ -135,8 +153,9 @@ class PSSM extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card_ id="map" className="map-container mt-3">
|
<Card_ id="map" className="map-container">
|
||||||
<MapContainer
|
<MapContainer
|
||||||
|
ref={this.mapRef}
|
||||||
center={this.state.center}
|
center={this.state.center}
|
||||||
zoom={this.state.zoom}
|
zoom={this.state.zoom}
|
||||||
style={{ width: "100%", height: "100%" }}
|
style={{ width: "100%", height: "100%" }}
|
||||||
@ -182,14 +201,19 @@ class PSSM extends React.Component {
|
|||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
|
|
||||||
<CustomZoomControl />
|
{/* <CustomZoomControl /> */}
|
||||||
<SelectMenu
|
<div className="custom-zoom-control">
|
||||||
ecowasCountries={ecowasCountries}
|
<button onClick={this.zoomIn}>+</button>
|
||||||
recsaCountries={recsaCountries}
|
<button onClick={this.zoomOut}>-</button>
|
||||||
selectedCountry={selectedCountry}
|
<button onClick={this.resetMap}>*</button>
|
||||||
handleCountryChange={this.handleCountryChange}
|
</div>
|
||||||
></SelectMenu>
|
|
||||||
|
|
||||||
|
<SelectMenu
|
||||||
|
ecowasCountries={ecowasCountries}
|
||||||
|
recsaCountries={recsaCountries}
|
||||||
|
selectedCountry={selectedCountry}
|
||||||
|
handleCountryChange={this.handleCountryChange}
|
||||||
|
></SelectMenu>
|
||||||
|
|
||||||
<Legend />
|
<Legend />
|
||||||
</MapContainer>
|
</MapContainer>
|
||||||
|
10
src/Components/Layout/PSSM/PssmResources.jsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Card_ from '../../UI/Card_/Card_';
|
||||||
|
const PssmResources = (props) => {
|
||||||
|
const {className} = props;
|
||||||
|
return (
|
||||||
|
<Card_ className={className}>PSSM Resources</Card_>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PssmResources
|
@ -1,12 +1,28 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Container from "react-bootstrap/Container";
|
import Container from "react-bootstrap/Container";
|
||||||
|
import Row from "react-bootstrap/Row";
|
||||||
|
import Col from "react-bootstrap/Col";
|
||||||
import Blurb from "../Layout/PSSM/Blurb";
|
import Blurb from "../Layout/PSSM/Blurb";
|
||||||
import PSSM from "../Layout/PSSM/PSSM";
|
import PSSM from "../Layout/PSSM/PSSM";
|
||||||
|
import ImageGallery from "../Layout/PSSM/ImageGallery";
|
||||||
|
import ImpactStories from "../Layout/PSSM/ImpactStories";
|
||||||
|
import PssmResources from "../Layout/PSSM/PssmResources";
|
||||||
const Treaties = () => {
|
const Treaties = () => {
|
||||||
return (
|
return (
|
||||||
<Container className="p-5">
|
<Container fluid className="p-5">
|
||||||
<Blurb></Blurb>
|
<Row>
|
||||||
<PSSM></PSSM>
|
<Col sm={7}>
|
||||||
|
<Blurb></Blurb>
|
||||||
|
<ImpactStories className="mt-3 p-3"></ImpactStories>
|
||||||
|
<PssmResources className="mt-3 p-3"></PssmResources>
|
||||||
|
</Col>
|
||||||
|
<Col sm={5}>
|
||||||
|
<PSSM></PSSM>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<ImageGallery className="mt-3"></ImageGallery>
|
||||||
|
</Row>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
8
src/Styles/Layout/_blurb.scss
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.blurb {
|
||||||
|
width: 100%; /* Adjust the width as needed */
|
||||||
|
height: 50%; /* Adjust the height as needed */
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #ccc; /* Optional: Add a border for better visibility */
|
||||||
|
padding: 10px; /* Optional: Add some padding */
|
||||||
|
box-sizing: border-box; /* Ensure padding is included in the element's total width and height */
|
||||||
|
}
|
13
src/Styles/Layout/_nav_bar.scss
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.nav-bar{
|
||||||
|
background-color: $primary-accent-color !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-bar-title{
|
||||||
|
font-size: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-bar-item{
|
||||||
|
font-size: 26px;
|
||||||
|
color: $primary-text-color;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
49
src/Styles/Layout/_pssm_image_gallery.scss
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
.image-gallery {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thumbnail {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
object-fit: cover;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thumbnail:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
position: relative;
|
||||||
|
max-width: 90%;
|
||||||
|
max-height: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
color: white;
|
||||||
|
font-size: 30px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-size-image {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
@ -17,6 +17,9 @@
|
|||||||
@import 'Layout/_map_info_box';
|
@import 'Layout/_map_info_box';
|
||||||
@import 'Layout/_map_info_box2';
|
@import 'Layout/_map_info_box2';
|
||||||
@import 'Layout/_legend';
|
@import 'Layout/_legend';
|
||||||
|
@import 'Layout/_blurb';
|
||||||
|
@import 'Layout/_pssm_image_gallery';
|
||||||
|
@import 'Layout/_nav_bar';
|
||||||
|
|
||||||
// Import other layout partials...
|
// Import other layout partials...
|
||||||
|
|
||||||
|
BIN
src/img/pssm/1000013063.jpg
Normal file
After Width: | Height: | Size: 476 KiB |
BIN
src/img/pssm/1000013066.jpg
Normal file
After Width: | Height: | Size: 549 KiB |
BIN
src/img/pssm/1000013069.jpg
Normal file
After Width: | Height: | Size: 488 KiB |
BIN
src/img/pssm/1000013072.jpg
Normal file
After Width: | Height: | Size: 520 KiB |
BIN
src/img/pssm/1000013075.jpg
Normal file
After Width: | Height: | Size: 455 KiB |
BIN
src/img/pssm/1000013078.jpg
Normal file
After Width: | Height: | Size: 495 KiB |
BIN
src/img/pssm/Bild1_Nikhil.jpg
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
src/img/pssm/Bild2_Nikhil.jpg
Normal file
After Width: | Height: | Size: 95 KiB |
BIN
src/img/pssm/Group of Senior Instructors and Instructors.jpg
Normal file
After Width: | Height: | Size: 14 MiB |
BIN
src/img/pssm/Image 1.jpg
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
src/img/pssm/Opening 2.jpg
Normal file
After Width: | Height: | Size: 141 KiB |
BIN
src/img/pssm/Storekeeper and Policewoman.jpg
Normal file
After Width: | Height: | Size: 240 KiB |
BIN
src/img/pssm/bild.jpg
Normal file
After Width: | Height: | Size: 1.5 MiB |