Add salw_client

This commit is contained in:
louai98 2024-11-28 16:11:59 +01:00
parent 46d314d9d0
commit c887b964da
149 changed files with 58494 additions and 0 deletions

23
salw_client/.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

1
salw_client/.npmrc Normal file
View File

@ -0,0 +1 @@
//registry.npmjs.org/:_authToken=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

37
salw_client/Dockerfile Normal file
View File

@ -0,0 +1,37 @@
# Front-End
# frontend/Dockerfile
# Build stage
FROM node:18 AS build
# Set working directory
WORKDIR /app
# Copy package.json and package-lock.json
COPY package.json ./
COPY package-lock.json ./
# Install dependencies
RUN npm install
# Copy the rest of the application code
COPY . ./
# Build the React app
RUN npm run build
# Production stage
FROM nginx:stable-alpine
# Copy the build output to nginx html directory
COPY --from=build /app/build /usr/share/nginx/html
# Copy the custom Nginx configuration file
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Expose port 80
EXPOSE 80
# Start nginx
CMD ["nginx", "-g", "daemon off;"]

70
salw_client/README.md Normal file
View File

@ -0,0 +1,70 @@
# Getting Started with Create React App
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `npm start`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
The page will reload when you make changes.\
You may also see any lint errors in the console.
### `npm test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `npm run build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `npm run eject`
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
### Analyzing the Bundle Size
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
### Making a Progressive Web App
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
### Advanced Configuration
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
### Deployment
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
### `npm run build` fails to minify
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)

21
salw_client/nginx.conf Normal file
View File

@ -0,0 +1,21 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
location / {
# All requests are routed to index.html
try_files $uri /index.html;
}
# Optional: Cache static files to improve performance
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg|otf|webp)$ {
expires 6M;
access_log off;
add_header Cache-Control "public";
}
}

20317
salw_client/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

55
salw_client/package.json Normal file
View File

@ -0,0 +1,55 @@
{
"name": "salw_client",
"version": "0.1.0",
"private": true,
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/react-fontawesome": "^0.2.1",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.7.7",
"bootstrap": "^5.3.2",
"dompurify": "^3.1.4",
"html-react-parser": "^5.1.10",
"leaflet": "^1.9.4",
"leaflet.bigimage": "^1.0.1",
"node-sass": "^7.0.3",
"react": "^18.2.0",
"react-bootstrap": "^2.9.1",
"react-dom": "^18.2.0",
"react-leaflet": "^4.2.1",
"react-query": "^3.39.3",
"react-router-dom": "^6.22.3",
"react-scripts": "5.0.1",
"react-select": "^5.8.0",
"sass": "^1.77.0",
"swiper": "^11.0.2",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""
/>
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

41
salw_client/src/App.css Normal file
View File

@ -0,0 +1,41 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

19
salw_client/src/App.js Normal file
View File

@ -0,0 +1,19 @@
import logo from "./logo.svg";
import "./App.css";
import NavBarSalw from "./Components/Layout/NavBarSalw/NavBarSalw.js";
import { QueryClient, QueryClientProvider } from "react-query";
import { DataProvider } from "./Context/DataContext.js";
const queryClient = new QueryClient();
const App = () => {
return (
<QueryClientProvider client={queryClient}>
<DataProvider>
<NavBarSalw></NavBarSalw>
</DataProvider>
</QueryClientProvider>
);
};
export default App;

View File

@ -0,0 +1,8 @@
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

View File

@ -0,0 +1,25 @@
.content-wrapper {
position: relative;
max-height: 150px; /* Adjust this value to the desired truncated height */
overflow: hidden;
transition: max-height 0.3s ease;
}
.content-wrapper.expanded {
max-height: none;
}
.read-more {
display: block;
margin-top: 10px;
color: blue;
background: none;
border: none;
cursor: pointer;
text-decoration: underline;
font-size: 1rem;
}
.read-more:focus {
outline: none;
}

View File

@ -0,0 +1,25 @@
import React, { useState } from "react";
import "./TruncateContent.css";
const TruncateContent = ({ children }) => {
const [isExpanded, setIsExpanded] = useState(false);
const toggleReadMore = () => {
setIsExpanded(!isExpanded);
};
return (
<>
<div
className={`content-wrapper ${isExpanded ? "expanded" : "truncated"}`}
>
{children}
</div>
<button className="read-more" onClick={toggleReadMore}>
{isExpanded ? "Read Less" : "Read More"}
</button>
</>
);
};
export default TruncateContent;

View File

@ -0,0 +1,58 @@
import React, { useState, useEffect } from "react";
import Africa from "../../../Data/TestAfrica.geojson";
import Dropdown from "react-bootstrap/Dropdown";
import DropdownButton from "react-bootstrap/DropdownButton";
import Select from "react-select";
const AfricaMapFilters = ({ handleCountrySelect }) => {
const [africaCountries, setAfricaCountries] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [selectedOption, setSelectedOption] = useState(null);
useEffect(() => {
const fetchAfricaCountries = async () => {
try {
const response = await fetch(Africa);
const data = await response.json();
setAfricaCountries(
data.features.map((country) => ({
value: country.properties.name,
label: country.properties.name,
target: country,
}))
);
setLoading(false);
} catch (error) {
setError(error);
setLoading(false);
}
};
fetchAfricaCountries();
}, []);
const handleChange = (selectedOption) => {
setSelectedOption(selectedOption);
handleCountrySelect(selectedOption);
};
return (
<div>
AfricaMapFilters
<div>
<h3>Select a country:</h3>
<Select
value={selectedOption}
onChange={handleChange}
options={africaCountries}
isSearchable={true}
placeholder="Search..."
menuPortalTarget={document.body}
/>
</div>
</div>
);
};
export default AfricaMapFilters;

View File

@ -0,0 +1,36 @@
import React from "react";
import Carousel from "react-bootstrap/Carousel";
import Container from "react-bootstrap/esm/Container";
import Classes from "./CarouselsSalw.module.css";
import weapon1 from "../../../img/weapon1.png";
import weapon2 from "../../../img/weapon2.png";
import weapon3 from "../../../img/weapon3.png";
import weapon4 from "../../../img/weapon4.png";
import weapon5 from "../../../img/weapon5.png";
const CarouselsSalw = () => {
return (
<Container className="mt-5">
<Carousel className={`${Classes.swiper} text-center w-75 m-auto`}>
<Carousel.Item>
<img src={weapon1} alt="" className="d-block mx-auto" />
</Carousel.Item>
<Carousel.Item>
<img src={weapon2} alt="" className="d-block mx-auto"/>
</Carousel.Item>
<Carousel.Item>
<img src={weapon3} alt="" className="d-block mx-auto"/>
</Carousel.Item>
<Carousel.Item>
<img src={weapon4} alt="" className="d-block mx-auto"/>
</Carousel.Item>
<Carousel.Item>
<img src={weapon5} alt="" className="d-block mx-auto"/>
</Carousel.Item>
</Carousel>
</Container>
);
};
export default CarouselsSalw;

View File

@ -0,0 +1,6 @@
.swiper {
border: solid 1px #ccc;
border-radius: 15px;
background-color: #ccc;
height: 100%;
}

View File

@ -0,0 +1,816 @@
import React, { createRef } from "react";
import { MapContainer, GeoJSON, Marker, Tooltip } from "react-leaflet";
import L from "leaflet";
import Africa from "../../../Data/ControlinAfrica.geojson";
import Orgs from "../../../Data/Orgs.geojson";
import "../../../Styles/main.scss";
import { CountryStyle, CountrySelectedStyle } from "./countryStyles";
import MapInfoBox from "./MapInfoBox"; // Import the InfoBox component
import MarkerIcon from "./MarkerIcon";
import CountryPopup from "./CountryPopup";
import FilterBox from "./FilterBox";
import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import SelectedFilters from "./SelectedFilters";
import TreatyInfoBox from "./TreatyInfoBox";
import Icon1 from "../../../Icons/icon1.svg";
import Icon2 from "../../../Icons/icon2.svg";
import Icon3 from "../../../Icons/icon3.svg";
import Icon4 from "../../../Icons/icon4.svg";
import Icon5 from "../../../Icons/icon5.svg";
import Icon6 from "../../../Icons/icon6.svg";
import Icon7 from "../../../Icons/icon7.svg";
import Icon8 from "../../../Icons/icon8.svg";
import Icon9 from "../../../Icons/icon9.svg";
import Icon10 from "../../../Icons/icon10.svg";
import Icon11 from "../../../Icons/icon11.svg";
import Icon12 from "../../../Icons/icon12.svg";
import Icon13 from "../../../Icons/icon13.svg";
import Icon14 from "../../../Icons/icon14.svg";
import Icon15 from "../../../Icons/icon15.svg";
import Icon16 from "../../../Icons/icon16.svg";
import Icon17 from "../../../Icons/icon17.svg";
import Icon18 from "../../../Icons/icon18.svg";
import Icon19 from "../../../Icons/icon19.svg";
import Icon20 from "../../../Icons/icon20.svg";
import Icon21 from "../../../Icons/icon21.svg";
import Icon22 from "../../../Icons/icon22.svg";
import Icon23 from "../../../Icons/icon23.svg";
import Icon24 from "../../../Icons/icon24.svg";
import Icon25 from "../../../Icons/icon25.svg";
import Icon26 from "../../../Icons/icon26.svg";
import Card_ from "../../UI/Card_/Card_";
const iconMap = {
Icon1: Icon1,
Icon2: Icon2,
Icon3: Icon3,
Icon4: Icon4,
Icon5: Icon5,
Icon6: Icon6,
Icon7: Icon7,
Icon8: Icon8,
Icon9: Icon9,
Icon10: Icon10,
Icon11: Icon11,
Icon12: Icon12,
Icon13: Icon13,
Icon14: Icon14,
Icon15: Icon15,
Icon16: Icon16,
Icon17: Icon17,
Icon18: Icon18,
Icon19: Icon19,
Icon20: Icon20,
Icon21: Icon21,
Icon22: Icon22,
Icon23: Icon23,
Icon24: Icon24,
Icon25: Icon25,
Icon26: Icon26,
};
class ControlInAfricaMap extends React.Component {
constructor(props) {
super(props);
this.mapRef = createRef(); // Create a ref to store the MapContainer instance
this.state = {
africaCountries: null, // The GeoJSON data for the African countries
countriesNames: [], // The names of the countries for select list
regional_organisations: [], // The regional organisations data
geographical_regions: [], // The geographical regions data
regional_treaties: [], // The regional treaties data
international_treaties: [], // The international treaties data
internationalIntsruments: [], // The international instruments data
africanIntsruments: [], // The african instruments data
loading: true,
error: null,
center: [3, 15],
zoom: this.getZoomLevel(window.innerWidth),
scrollWheelZoom: false,
zoomControl: false,
openedTooltipLayer: null,
selectedCountry: "", // The name of the selected country
selectedRegion: "", // The name of the selected region
selectedTreaty: "", // The name of the selected treaty
selectedTreatyOfficialName: "", // For the Slescted filters box
selectedCountriesNamesRegions: [],
selectedCountriesNamesTreaties: [],
selectedCountriesFeaturesRegions: [],
selectedCountriesFeaturesTreaties: [],
selectedCommonCountries: [],
selectedCountryColor: "yellow",
selectedIcon: "none",
currentStatuesTreaty: "",
prevStatuesTreaty: "",
infoBox: [],
showInfoBox: false,
};
}
componentDidMount() {
this.fetchData();
window.addEventListener("resize", this.handleResize);
if (L.control.bigImage) {
L.control.bigImage({ position: 'topright' }).addTo(this.mapRef);
}
}
componentWillUnmount() {
window.removeEventListener("resize", this.handleResize);
}
fetchData = async () => {
try {
const response = await fetch(Africa);
const data = await response.json();
this.setState(
{
africaCountries: data.features,
countriesNames: data.features
.map((feature) => feature.properties.name)
.sort(),
loading: false,
},
() => {}
);
} catch (error) {
this.setState({
error: error,
loading: false,
});
}
try {
//console.log("fetching data");
const response = await fetch(Orgs); // Ensure this is a valid URL
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
// Replace icon names with actual icon objects
const regional_treaties = data.regional_treaties.map((treaty) => ({
...treaty,
icon_eligible: iconMap[treaty.icon_eligible] || null,
icon_signed: iconMap[treaty.icon_signed] || null,
icon_ratified: iconMap[treaty.icon_ratified] || null,
}));
const international_treaties = data.international_treaties.map(
(treaty) => ({
...treaty,
icon_eligible: iconMap[treaty.icon_eligible] || null,
icon_signed: iconMap[treaty.icon_signed] || null,
icon_ratified: iconMap[treaty.icon_ratified] || null,
})
);
const internationalIntsruments = data.internationalIntsruments.map(
(instrument) => ({
...instrument,
icon: iconMap[instrument.icon] || null,
})
);
const africanIntsruments = data.africanIntsruments.map((instrument) => ({
...instrument,
icon: iconMap[instrument.icon] || null,
}));
this.setState(
{
regional_organisations: data.regional_organisations,
geographical_regions: data.geographical_regions,
regional_treaties,
international_treaties,
internationalIntsruments,
africanIntsruments,
},
() => {
// Callback after state has been updated (optional)
}
);
} catch (error) {
//console.error("Error fetching the JSON file:", error);
}
};
getZoomLevel = () => {
const screenWidth = window.innerWidth;
//console.log(screenWidth);
if (screenWidth <= 800) {
//console.log("small screen");
return 3;
} else if (screenWidth <= 1024) {
return 4;
} else {
return 4;
}
};
handleResize = () => {
this.setState({
zoom: this.getZoomLevel(window.innerWidth),
});
};
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);
}
};
handleCountryChange = (e) => {
const countryName = e.target.value || e.target.getAttribute("data-country");
const { selectedCountry } = this.state;
if (countryName === selectedCountry) {
this.setState({ selectedCountry: "" });
return;
}
this.setState({ selectedCountry: countryName }, () => {
//this.openTooltipForCountry(countryName);
});
};
onEachFeature = (feature, layer) => {
// Bind event to layer
layer.on({
//mouseover: this.onMouseOver,
//mouseout: this.onMouseOut,
click: this.onMouseClick,
});
};
// To Do: Delete this function
openTooltipForCountry = (countryName) => {
const { africaCountries } = this.state;
if (!africaCountries) return;
const feature = africaCountries.find(
(feature) => feature.properties.name === countryName
);
if (!feature) return;
const { openedTooltipLayer } = this.state;
if (openedTooltipLayer) {
openedTooltipLayer.closeTooltip(); // Close the previously opened tooltip
}
const layer = L.geoJSON(feature);
// Update the state to store the currently opened tooltip
this.setState({ openedTooltipLayer: layer });
};
onMouseClick = (e) => {
const countryName = e.target.feature.properties.name;
if (countryName === this.state.selectedCountry) {
this.setState({
selectedCountry: "",
selectedRegion: "",
selectedTreaty: "",
selectedTreatyOfficialName: "",
selectedCountriesNamesRegions: [],
selectedCountriesNamesTreaties: [],
selectedCountriesFeaturesRegions: [],
selectedCountriesFeaturesTreaties: [],
selectedCountryColor: "yellow",
prevStatuesTreaty: "",
infoBox: [],
showInfoBox: false,
});
this.props.updateCountryID(null);
return;
}
this.setState({
selectedCountry: countryName,
selectedRegion: "",
selectedTreaty: "",
selectedTreatyOfficialName: "",
selectedCountriesNamesRegions: [],
selectedCountriesNamesTreaties: [],
selectedCountriesFeaturesRegions: [],
selectedCountriesFeaturesTreaties: [],
selectedCountryColor: "yellow",
prevStatuesTreaty: "",
infoBox: [],
showInfoBox: false,
});
this.props.updateCountryID(e.target.feature.properties.id);
};
handleOrganizationClick = (name, color) => {
const { selectedRegion, prevStatuesTreaty, africaCountries } = this.state;
if (selectedRegion === name) {
//console.log("same");
this.setState({
selectedCountriesNamesRegions: [],
selectedCountriesNamesTreaties: [],
selectedCountryColor: "yellow",
selectedCountry: "",
selectedRegion: "",
showInfoBox: false,
currentStatuesTreaty: "",
});
return;
}
if (prevStatuesTreaty) {
//console.log("change");
this.setState({
selectedCountriesNamesTreaties: [],
selectedCountry: "",
currentStatuesTreaty: "",
});
}
let selectedCountriesNamesRegions = [];
let selectedCountriesFeaturesRegions = [];
africaCountries.forEach((feature) => {
if (feature.properties[name] === 1) {
selectedCountriesNamesRegions.push(feature.properties.name);
selectedCountriesFeaturesRegions.push(feature);
}
});
this.setState({
selectedCountriesNamesRegions,
selectedCountryColor: color,
selectedCountry: "",
selectedRegion: name,
selectedCountriesFeaturesRegions,
selectedTreaty: "",
selectedTreatyOfficialName: "",
showInfoBox: true,
});
};
handleTreatiesClick = (name, status, official_name) => {
const {
selectedRegion,
selectedTreaty,
selectedCountriesNamesRegions,
prevStatuesTreaty,
africaCountries,
regional_treaties,
international_treaties,
internationalIntsruments,
africanIntsruments,
currentStatuesTreaty,
} = this.state;
// get the icon of the selected treaty based on the name and status of the treaty
//console.log(name, status);
let org =
regional_treaties.find((org) => org.name2 === name) ||
international_treaties.find((org) => org.name2 === name);
let instrument =
internationalIntsruments.find(
(instrument) => instrument.name2 === name
) || africanIntsruments.find((instrument) => instrument.name2 === name);
const selectedIcon = org
? org[`icon_${status.toLowerCase()}`] || "none"
: instrument
? instrument[`icon`] || "none"
: "none";
this.setState({
selectedIcon,
currentStatuesTreaty: status,
});
// console.log(status, ":", currentStatuesTreaty, prevStatuesTreaty);
// if the same treaty is selected previously and the region is not selected
// then the treaty will be deselected
if (
selectedTreaty === name &&
prevStatuesTreaty === status &&
selectedRegion === ""
) {
//console.log("1");
this.setState({
selectedCountriesNamesRegions: [],
selectedCountriesNamesTreaties: [],
selectedCountryColor: "yellow",
selectedCountry: "",
selectedTreaty: "",
selectedTreatyOfficialName: "",
currentStatuesTreaty: "",
prevStatuesTreaty: "",
prevStatuesRegion: "",
selectedIcon: "none",
showInfoBox: false,
});
return;
}
// if the same treaty is selected previously and the region is selected
// then the treaty will be deselected
if (selectedTreaty === name && prevStatuesTreaty === status) {
//console.log("2");
this.setState({
selectedCountriesNamesTreaties: [],
selectedCountry: "",
selectedTreaty: "",
selectedTreatyOfficialName: "",
prevStatuesTreaty: "",
currentStatuesTreaty: "",
selectedIcon: "none",
showInfoBox: true,
});
return;
}
let selectedCountriesNamesTreaties = [];
let selectedCountriesFeaturesTreaties = [];
africaCountries.forEach((feature) => {
if (
feature.properties[name] === 1 ||
feature.properties[name] === status
) {
selectedCountriesNamesTreaties.push(feature.properties.name);
selectedCountriesFeaturesTreaties.push(feature);
}
});
// if the region is selected then the treaty will be selected based on the
// intersection of the region and the treaty
if (selectedRegion) {
//console.log("intersect");
const intersection = selectedCountriesNamesTreaties.filter((country) =>
selectedCountriesNamesRegions.includes(country)
);
const selectedCommonCountries = selectedCountriesNamesTreaties
.filter((country) => selectedCountriesNamesRegions.includes(country))
.map((country) => ({
country,
status,
}));
this.setState({
selectedCountriesNamesTreaties: intersection,
selectedCountry: "",
selectedTreaty: name,
selectedTreatyOfficialName: official_name,
currentStatuesTreaty: status,
prevStatuesTreaty: status,
showInfoBox: true,
selectedCommonCountries,
});
return;
}
this.setState({
selectedCountriesNamesTreaties,
selectedCountry: "",
selectedTreaty: name,
selectedTreatyOfficialName: official_name,
currentStatuesTreaty: status,
prevStatuesTreaty: status,
selectedCountriesFeaturesTreaties,
});
// if region and treaty selected
if (
this.state.selectedRegion &&
regional_treaties.some((org) => org.name2 === name)
) {
this.setState({
selectedTreaty: name,
selectedTreatyOfficialName: official_name,
currentStatuesTreaty: status,
});
}
};
regionalOrganisationStatistics = () => {
const {
selectedCountriesFeaturesRegions,
regional_treaties,
international_treaties,
internationalIntsruments,
africanIntsruments,
} = this.state;
// Helper function to process treaties
const processTreaties = (treaties) => {
return treaties.map((org) => {
let countriesSigned = 0;
let countriesEligible = 0;
let countriesRatified = 0;
selectedCountriesFeaturesRegions.forEach((feature) => {
const status = feature.properties[org.name2];
if (status === "Signed") {
countriesSigned++;
} else if (status === "Eligible") {
countriesEligible++;
} else if (status === "Ratified") {
countriesRatified++;
}
});
return {
name: org.name,
signed: countriesSigned,
eligible: countriesEligible,
ratified: countriesRatified,
};
});
};
// Helper function to process instruments
const processInstruments = (instruments) => {
return instruments.map((instrument) => {
const countris = selectedCountriesFeaturesRegions.filter(
(feature) => feature.properties[instrument.name2] === 1
);
return {
name: instrument.name,
countries: countris.length,
};
});
};
const organisationsRegionalTreaties = processTreaties(regional_treaties);
const organisationsInternationalTreaties = processTreaties(
international_treaties
);
const internationalIntsruments_ = processInstruments(
internationalIntsruments
);
const africanIntsruments_ = processInstruments(africanIntsruments);
return {
organisationsRegionalTreaties,
organisationsInternationalTreaties,
internationalIntsruments_,
africanIntsruments_,
};
};
// Define the function to determine the style
getFeatureStyle = (
feature,
selectedCountry,
selectedCountriesNamesRegions,
selectedCountriesNamesTreaties,
selectedCountryColor
) => {
const { name } = feature.properties;
// select one country
if (name === selectedCountry) {
//console.log("one country selected");
return CountrySelectedStyle(selectedCountryColor);
}
const inSelectedRegions = selectedCountriesNamesRegions.includes(name);
const inSelectedTreaties = selectedCountriesNamesTreaties.includes(name);
// select one region
if (inSelectedRegions && !selectedCountriesNamesTreaties.length) {
//console.log("region selected");
return CountrySelectedStyle(selectedCountryColor);
}
// select one treaty
if (inSelectedRegions && !inSelectedTreaties) {
//console.log("region and treaty selected 1");
return CountrySelectedStyle(selectedCountryColor);
}
// select region and treaty
if (inSelectedRegions && inSelectedTreaties) {
//console.log("region and treaty selected 2");
return CountrySelectedStyle(selectedCountryColor, 0.7);
}
// default style
//console.log("default");
return CountryStyle();
};
render() {
const {
africaCountries,
loading,
error,
zoom,
zoomControl,
center,
scrollWheelZoom,
showInfoBox,
countriesNames,
selectedCountry,
selectedCountriesNamesRegions,
selectedCountriesNamesTreaties,
currentStatuesTreaty,
selectedCountryColor,
selectedRegion,
selectedTreaty,
selectedTreatyOfficialName,
selectedIcon,
geographical_regions,
regional_organisations,
regional_treaties,
international_treaties,
internationalIntsruments,
africanIntsruments,
} = this.state;
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
return (
<Container fluid>
<Row>
<Col className="filter-section" sm={2}>
<FilterBox
selectedCountry={selectedCountry}
countriesNames={countriesNames}
handleCountryChange={this.handleCountryChange}
handleOrganizationClick={this.handleOrganizationClick}
handleTreatiesClick={this.handleTreatiesClick}
geographical_regions={geographical_regions}
regional_organisations={regional_organisations}
regional_treaties={regional_treaties}
international_treaties={international_treaties}
internationalIntsruments={internationalIntsruments}
africanIntsruments={africanIntsruments}
></FilterBox>
</Col>
<Col className="map-section" sm={10}>
<div id="map" className="map-container">
<MapContainer
center={center}
zoom={zoom}
ref={this.mapRef}
zoomControl={zoomControl}
style={{ width: "100%", height: "100%" }}
scrollWheelZoom={scrollWheelZoom}
>
{africaCountries && (
<>
<GeoJSON
ref={this.geoJsonLayerRef}
onEachFeature={this.onEachFeature}
id="africa-map"
style={(feature) =>
this.getFeatureStyle(
feature,
selectedCountry,
selectedCountriesNamesRegions,
selectedCountriesNamesTreaties,
selectedCountryColor
)
}
key="africa-map"
data={africaCountries}
/>
</>
)}
{selectedCountry &&
africaCountries.map((feature) => {
if (feature.properties.name === selectedCountry) {
return (
<Marker
key={feature.properties.name}
position={[
feature.properties.y,
feature.properties.x,
]}
>
<Tooltip
direction="bottom"
offset={[-13, 27]}
opacity={1}
permanent
className="tooltip-custom"
>
<CountryPopup
feature={feature}
regional_organisations={regional_organisations}
regional_treaties={regional_treaties}
international_treaties={international_treaties}
></CountryPopup>
</Tooltip>
</Marker>
);
}
})}
{selectedTreaty &&
selectedCountriesNamesTreaties &&
africaCountries.map((feature, index) => {
if (
selectedCountriesNamesTreaties.includes(
feature.properties.name
)
) {
return (
<MarkerIcon
key={index}
position={[
feature.properties.y,
feature.properties.x,
]}
icon={selectedIcon}
></MarkerIcon>
);
}
})}
<div className="custom-zoom-control">
<button onClick={this.zoomIn}>+</button>
<button onClick={this.zoomOut}>-</button>
<button onClick={this.resetMap}>*</button>
</div>
<div className="country-select">
<select
onChange={this.handleCountryChange}
value={selectedCountry}
>
<option value="">Select a country</option>
{countriesNames.map((country, index) => (
<option key={index} value={country}>
{country}
</option>
))}
</select>
</div>
{selectedRegion || selectedTreatyOfficialName ? (
<SelectedFilters
selectedRegion={selectedRegion}
selectedTreatyOfficialName={selectedTreatyOfficialName}
></SelectedFilters>
) : (
<></>
)}
{selectedRegion && selectedTreaty && (
<TreatyInfoBox
selectedRegion={selectedRegion}
selectedTreatyOfficialName={selectedTreatyOfficialName}
currentStatuesTreaty={currentStatuesTreaty}
selectedCountriesNamesTreaties={
selectedCountriesNamesTreaties
}
handleCountryChange={this.handleCountryChange}
></TreatyInfoBox>
)}
{showInfoBox && (
<MapInfoBox
className="info-box"
selectedCountryColor={selectedCountryColor}
selectedRegion={selectedRegion}
info={this.regionalOrganisationStatistics()}
></MapInfoBox>
)}
</MapContainer>
</div>
</Col>
</Row>
</Container>
);
}
}
export default ControlInAfricaMap;

View File

@ -0,0 +1,90 @@
import React from "react";
import "../../../Styles/main.scss";
import Icon1 from "../../../Icons/icon1.svg";
import Icon16 from "../../../Icons/icon16.svg";
import Icon20 from "../../../Icons/icon20.svg";
const findColorByName = (name, regional_organisations) => {
const org = regional_organisations.find((org) => org.name === name);
return org ? org.color : ""; // Return color value if found, otherwise return an empty string
};
const CountryPopup = (props) => {
const {
feature,
regional_organisations,
regional_treaties,
international_treaties,
} = props;
return (
<>
<h5>{feature.properties.name}</h5>
<div className="matrix">
{regional_organisations.map((org) => (
<div
key={org.name}
className="rectangle"
style={
feature.properties[org.name] === 1
? {
backgroundColor: findColorByName(org.name, regional_organisations),
}
: {}
}
title={org.name}
></div>
))}
</div>
<div className="matrix-treaties-map">
{regional_treaties.map((treaty) => (
<div key={treaty.name2}>
<img
src={
treaty["icon_" + feature.properties[treaty.name2].toLowerCase()]
}
alt=""
srcSet="No Image"
className="img-fluid"
/>
</div>
))}
</div>
<div className="matrix-treaties-map">
{international_treaties.map((treaty) => (
<div key={treaty.name2}>
<img
src={
treaty["icon_" + feature.properties[treaty.name2].toLowerCase()]
}
alt=""
srcSet="No Image"
className="img-fluid"
/>
</div>
))}
</div>
<div className="matrix-treaties-map">
<div>
{feature.properties.UNProgrammeofAction === 1 && (
<img src={Icon20} alt="" srcSet="" />
)}
</div>
<div>
{feature.properties.InternationalTracingInstrument === 1 && (
<img src={Icon16} alt="" srcSet="" />
)}
</div>
<div>
{feature.properties["StG-PoA"] === 1 && (
<img src={Icon1} alt="" srcSet="" />
)}
</div>
</div>
</>
);
};
export default CountryPopup;

View File

@ -0,0 +1,342 @@
import React, { useState, useEffect } from "react";
import Stack from "react-bootstrap/Stack";
import Card_ from "../../UI/Card_/Card_";
import { useAfricaData } from "../../../Context/DataContext";
import Icon1 from "../../../Icons/icon1.svg";
import Icon2 from "../../../Icons/icon2.svg";
import Icon3 from "../../../Icons/icon3.svg";
import Icon4 from "../../../Icons/icon4.svg";
import Icon5 from "../../../Icons/icon5.svg";
import Icon6 from "../../../Icons/icon6.svg";
import Icon7 from "../../../Icons/icon7.svg";
import Icon8 from "../../../Icons/icon8.svg";
import Icon9 from "../../../Icons/icon9.svg";
import Icon10 from "../../../Icons/icon10.svg";
import Icon11 from "../../../Icons/icon11.svg";
import Icon12 from "../../../Icons/icon12.svg";
import Icon13 from "../../../Icons/icon13.svg";
import Icon14 from "../../../Icons/icon14.svg";
import Icon15 from "../../../Icons/icon15.svg";
import Icon16 from "../../../Icons/icon16.svg";
import Icon17 from "../../../Icons/icon17.svg";
import Icon18 from "../../../Icons/icon18.svg";
import Icon19 from "../../../Icons/icon19.svg";
import Icon20 from "../../../Icons/icon20.svg";
import Icon21 from "../../../Icons/icon21.svg";
import Icon22 from "../../../Icons/icon22.svg";
import Icon23 from "../../../Icons/icon23.svg";
import Icon24 from "../../../Icons/icon24.svg";
import Icon25 from "../../../Icons/icon25.svg";
import Icon26 from "../../../Icons/icon26.svg";
const regional_organisations = [
{ name: "AU", color: "#b2df8a" },
{ name: "EAC", color: "#33a02c" },
{ name: "IGAD", color: "#fb9a99" },
{ name: "UMA", color: "#e31a1c" },
{ name: "COMESA", color: "#fdbf6f" },
{ name: "ECOWAS", color: "#ff7f00" },
{ name: "CEN-SAD", color: "#cab2d6" },
{ name: "SADC", color: "#6a3d9a" },
{ name: "ECCAS", color: "#ffff99" },
{ name: "ICGLR", color: "#b15928" },
{ name: "RECSA", color: "#a6cee3" },
{ name: "SARCOM", color: "#1f78b4" },
];
const regional_treaties = [
{
name: "Bamako Declaration",
name2: "BamakoDeclaration",
icon_eligible: Icon26,
icon_signed: Icon24,
icon_ratified: null,
},
{
name: "Kinshasa Convention",
name2: "KinshasaConvention",
icon_eligible: Icon4,
icon_signed: Icon6,
icon_ratified: Icon5,
},
{
name: "ECOWAS Convention",
name2: "ECOWASConvention",
icon_eligible: Icon2,
icon_signed: Icon3,
icon_ratified: null,
},
{
name: "Khartoum Declaration",
name2: "KhartoumDeclaration",
icon_eligible: Icon21,
icon_signed: Icon23,
icon_ratified: null,
},
{
name: "Nairobi Protocol",
name2: "NairobiProtocol",
icon_eligible: Icon22,
icon_signed: Icon25,
icon_ratified: null,
},
{
name: "SADC Firearms Protocol",
name2: "SADCFirearmsProtocol",
icon_eligible: Icon8,
icon_signed: Icon7,
icon_ratified: Icon9,
},
];
const international_treaties = [
{
name: "Arms Trade Treaty",
name2: "ArmsTradeTreaty",
icon_eligible: Icon19,
icon_signed: Icon17,
icon_ratified: Icon18,
},
{
name: "Firearms Protocol",
name2: "FirearmsProtocol",
icon_eligible: Icon12,
icon_signed: Icon10,
icon_ratified: Icon11,
},
{
name: "Wassenaar Agreement",
name2: "WassenaarAgreement",
icon_eligible: Icon15,
icon_signed: Icon13,
icon_ratified: Icon14,
},
];
const international_guidelines = [
{
name: "UN Programme of Action",
name2: "UNProgrammeofAction",
icon_eligible: Icon20,
},
{
name: "International Tracing Instrument",
name2: "InternationalTracingInstrument",
icon_eligible: Icon16,
},
];
const african_guidelines = [
{
name: "Silencing the Guns in Africa Programme of Action",
name2: "StG-PoA",
icon_eligible: Icon1,
},
];
const DetailesSection = (props) => {
const { data, error, isLoading } = useAfricaData();
const countryID = props.countryID;
const [selectedCountry, setSelectedCountry] = useState("");
const [selectedRegionalOrganisations, setSelectedRegionalOrganisations] =
useState([]);
const [selectedRegionalTreaties, setSelectedRegionalTreaties] = useState([]);
const [selectedInternationalTreaties, setSelectedInternationalTreaties] =
useState([]);
const [selectedInternationalGuidelines, setSelectedInternationalGuidelines] =
useState([]);
const [selectedAfricanGuidelines, setSelectedAfricanGuidelines] = useState(
[]
);
useEffect(() => {
if (data && countryID !== null) {
const foundCountry = data.features.find(
(item) => item.properties.id === countryID
);
setSelectedCountry(foundCountry);
const regionalOrgs = regional_organisations.filter(
(item) => foundCountry.properties[item.name] === 1
);
setSelectedRegionalOrganisations(regionalOrgs);
const regionalTreats = regional_treaties
.filter((item) => foundCountry.properties[item.name2] !== "0")
.map((item) => {
return {
...item,
state: foundCountry.properties[item.name2],
};
});
const internationalTreats = international_treaties
.filter((item) => foundCountry.properties[item.name2] !== "0")
.map((item) => {
return {
...item,
state: foundCountry.properties[item.name2],
};
});
const internationalGuidelines = international_guidelines.filter(
(item) => foundCountry.properties[item.name2] === 1
);
const africanGuidelines = african_guidelines.filter(
(item) => foundCountry.properties[item.name2] === 1
);
setSelectedRegionalTreaties(regionalTreats);
setSelectedInternationalTreaties(internationalTreats);
setSelectedInternationalGuidelines(internationalGuidelines);
setSelectedAfricanGuidelines(africanGuidelines);
}
}, [data, countryID]);
// useEffect(() => {
// console.log(selectedAfricanGuidelines)
// }, [selectedAfricanGuidelines]);
if (isLoading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error</div>;
}
return (
<Card_ className="mt-3 p-3">
{selectedCountry && (
<div>
<h2>{selectedCountry.properties.name}</h2>
<p>
<strong>Regional Organisations: </strong>
{selectedRegionalOrganisations.map((item) => {
return (
<span
key={item.name}
style={{ color: item.color, padding: "0 5px" }}
>
{item.name}
</span>
);
})}
</p>
<table className="table-sm table-bordered">
<tr>
<td>
<strong>Regional Treaties: </strong>
</td>
<td>
<table className="table">
{selectedRegionalTreaties.map((item) => {
return (
<tr key={item.name}>
<td>{item.name}</td>
<td>{item.state}</td>
<td>
<img
title={item.name}
src={item["icon_" + item.state.toLowerCase()]}
alt=""
srcSet="No Image"
className="section-icon"
/>
</td>
</tr>
);
})}
</table>
</td>
</tr>
<tr>
<td>
<strong>International Treaties: </strong>
</td>
<td>
<table className="table">
{selectedInternationalTreaties.map((item) => {
return (
<tr key={item.name}>
<td>{item.name}</td>
<td>{item.state}</td>
<td>
<img
title={item.name}
src={item["icon_" + item.state.toLowerCase()]}
alt=""
srcSet="No Image"
className="section-icon"
/>
</td>
</tr>
);
})}
</table>
</td>
</tr>
<tr>
<td>
<strong>International Guidelines & Instruments: </strong>
</td>
<td>
<table className="table">
{selectedInternationalGuidelines.map((item) => {
return (
<tr key={item.name}>
<td>
<span>{item.name}</span>
</td>
<td>
<img
title={item.name}
src={item["icon_eligible"]}
alt=""
srcSet="No Image"
className="section-icon"
/>
</td>
</tr>
);
})}
</table>
</td>
</tr>
<tr>
<td>
<strong>African Guidelines & Instrumentss: </strong>
</td>
<td>
<table className="table">
{selectedAfricanGuidelines.map((item) => {
return (
<tr key={item.name}>
<td>
<span>{item.name}</span>
</td>
<td>
<img
title={item.name}
src={item["icon_eligible"]}
alt=""
srcSet="No Image"
className="section-icon"
/>
</td>
</tr>
);
})}
</table>
</td>
</tr>
</table>
</div>
)}
</Card_>
);
};
export default DetailesSection;

View File

@ -0,0 +1,76 @@
import React, { useState } from "react";
import Col from "react-bootstrap/Col";
import "../../../Styles/main.scss";
import Geo_Org_Filter from "./Geo_Org_Filter";
import Reg_Org_Filter from "./Reg_Org_Filter";
import Treaties_Filter from "./Treaties_Filter";
import LanguageSelect from "./LanguageSelect";
import Button from "react-bootstrap/Button";
import Offcanvas from "react-bootstrap/Offcanvas";
const FilterBox = (props) => {
const [language, setLanguage] = useState("en");
const [show, setShow] = useState(false);
const handleLanguageChange = (language) => {
setLanguage(language);
};
const handleClose = () => setShow(false);
const toggleShow = () => setShow((s) => !s);
const {
handleOrganizationClick,
handleTreatiesClick,
regional_organisations,
regional_treaties,
international_treaties,
geographical_regions,
instruments,
internationalIntsruments,
africanIntsruments,
} = props;
return (
<>
<Button variant="primary" className="d-lg-none" onClick={toggleShow}>
Filters
</Button>
<Offcanvas show={show} onHide={handleClose} backdrop={false} scroll={true} responsive="lg">
<Offcanvas.Header closeButton>
<Offcanvas.Title>Filter Box</Offcanvas.Title>
</Offcanvas.Header>
<Offcanvas.Body>
<div className={`filters-box`}>
<LanguageSelect onLanguageChange={handleLanguageChange} />
<hr />
<Geo_Org_Filter
handleOrganizationClick={handleOrganizationClick}
geographical_regions={geographical_regions}
language={language}
/>
<hr />
<Reg_Org_Filter
handleOrganizationClick={handleOrganizationClick}
regional_organisations={regional_organisations}
language={language}
/>
<hr />
<Treaties_Filter
regional_treaties={regional_treaties}
international_treaties={international_treaties}
instruments={instruments}
internationalIntsruments={internationalIntsruments}
africanIntsruments={africanIntsruments}
handleTreatiesClick={handleTreatiesClick}
language={language}
/>
</div>
</Offcanvas.Body>
</Offcanvas>
</>
);
};
export default FilterBox;

View File

@ -0,0 +1,30 @@
import React from "react";
const Geo_Org_Filter = (props) => {
const headings = {
en: "Geographical Regions",
fr: "Régions Géographiques",
ar: "المناطق الجغرافية",
};
const { handleOrganizationClick, geographical_regions, language } =
props;
return (
<>
<h5>{headings[language] || headings['en']} </h5>
<div className="geographical-organisations">
{geographical_regions.map((org, index) => (
<div
key={org.name}
className="organization-item p-1"
style={{ backgroundColor: org.color }}
onClick={() => handleOrganizationClick(org.name, "", org.color)}
>
<div className="name">{org.name}</div>
</div>
))}
</div>
</>
);
};
export default Geo_Org_Filter;

View File

@ -0,0 +1,41 @@
import React, {useState} from "react";
import Button from 'react-bootstrap/Button';
import ButtonGroup from "react-bootstrap/ButtonGroup";
import ToggleButton from "react-bootstrap/ToggleButton";
const LanguageSelect = ({onLanguageChange}) => {
const [languageValue, setLanguageValue] = useState("en")
const languages = [
{ lang: "En", value: "en" },
{ lang: "Fr", value: "fr" },
{ lang: "ع", value: "ar" },
];
const handleLanguageChange = (language) => {
setLanguageValue(language);
onLanguageChange(language);
};
return (
<>
<ButtonGroup>
<Button variant="secondary" disabled>Language:</Button>{' '}
{languages.map((language, idx) => (
<ToggleButton
key={idx}
id={`language-${idx}`}
type="radio"
variant={"outline-secondary"}
name="language"
value={language.value}
checked={languageValue === language.value}
onChange={(e) => handleLanguageChange(e.currentTarget.value)}
>
{language.lang}
</ToggleButton>
))}
</ButtonGroup>
</>
);
};
export default LanguageSelect;

View File

@ -0,0 +1,202 @@
import React, { useState } from "react";
import Collapse from "react-bootstrap/Collapse";
import Card_ from "../../UI/Card_/Card_";
const MapInfoBox = (props) => {
const { internationalIntsruments_, africanIntsruments_ } = props.info;
const regional_treaties = props.info.organisationsRegionalTreaties;
const international_treaties = props.info.organisationsInternationalTreaties;
const [open, setOpen] = useState(true);
const [isHidden, setIsHidden] = useState(false);
return (
<Card_ className={props.className}>
<div
onClick={() => {
setOpen(!open);
setIsHidden(!isHidden);
}}
aria-controls="example-collapse-text"
aria-expanded={open}
style={{ display: "flex", justifyContent: "space-between" }}
>
<span>
<h3>{props.selectedRegion}</h3>
</span>
<span>
<h3>{isHidden ? "Show" : "Hide"}</h3>
</span>
</div>
<Collapse in={open}>
<div className="example-collapse-text">
<p>Number of countries</p>
<div className="table-responsive-sm">
<table className="table table-sm table-striped">
<thead>
<tr>
<th className="text-center" scope="col"></th>
<th className="text-center" scope="col">
Signed
</th>
<th className="text-center" scope="col">
Eligible
</th>
<th className="text-center" scope="col">
Ratified
</th>
</tr>
</thead>
<tbody>
{regional_treaties &&
regional_treaties.map((item, index) => {
return (
<tr key={index}>
<th scope="row">{item.name}</th>
<td
className="text-center"
style={
item.signed
? {
color: props.selectedCountryColor,
fontWeight: "bold",
fontSize: "16px",
}
: {}
}
>
{item.signed}
</td>
<td
className="text-center"
style={
item.eligible
? {
color: props.selectedCountryColor,
fontWeight: "bold",
fontSize: "16px",
}
: {}
}
>
{item.eligible}
</td>
<td
className="text-center"
style={
item.ratified
? {
color: props.selectedCountryColor,
fontWeight: "bold",
fontSize: "16px",
}
: {}
}
>
{item.ratified}
</td>
</tr>
);
})}
{international_treaties &&
international_treaties.map((item, index) => {
return (
<tr key={index}>
<th scope="row">{item.name}</th>
<td
className="text-center"
style={
item.signed
? {
color: props.selectedCountryColor,
fontWeight: "bold",
fontSize: "16px",
}
: {}
}
>
{item.signed}
</td>
<td
className="text-center"
style={
item.eligible
? {
color: props.selectedCountryColor,
fontWeight: "bold",
fontSize: "16px",
}
: {}
}
>
{item.eligible}
</td>
<td
className="text-center"
style={
item.ratified
? {
color: props.selectedCountryColor,
fontWeight: "bold",
fontSize: "16px",
}
: {}
}
>
{item.ratified}
</td>
</tr>
);
})}
</tbody>
</table>
</div>
{internationalIntsruments_ &&
internationalIntsruments_.map((item, index) => {
return (
<p className="mb-1" key={index}>
<strong>{item.name}:</strong>{" "}
<span
style={
item.countries
? {
color: props.selectedCountryColor,
fontWeight: "bold",
fontSize: "16px",
}
: {}
}
>
{item.countries}
</span>
</p>
);
})}
{africanIntsruments_ &&
africanIntsruments_.map((item, index) => {
return (
<p className="mb-1" key={index}>
<strong>{item.name}:</strong>{" "}
<span
style={
item.countries
? {
color: props.selectedCountryColor,
fontWeight: "bold",
fontSize: "16px",
}
: {}
}
>
{item.countries}
</span>
</p>
);
})}
</div>
</Collapse>
</Card_>
);
};
export default MapInfoBox;

View File

@ -0,0 +1,22 @@
import React from "react";
import L from "leaflet";
import { Marker } from "react-leaflet";
const MarkerIcon = (props) => {
return (
<Marker
key={props.index}
position= {props.position}
icon={
new L.Icon({
iconUrl: props.icon,
iconRetinaUrl: props.icon,
iconSize: [35, 35],
className: "leaflet-div-icon",
})
}
></Marker>
);
};
export default MarkerIcon;

View File

@ -0,0 +1,26 @@
import React from "react";
const Reg_Org_Filter = (props) => {
const { handleOrganizationClick, regional_organisations, language } = props;
return (
<div>
{language === "en" && <h5>Regional Organisations</h5>}
{language === "fr" && <h5>Organisations internationales</h5>}
{language === "ar" && <h5>المنظمات الإقليمية</h5>}
<div className="regional-organisations">
{regional_organisations.map((org, index) => (
<div
key={org.name}
className="organization-item"
style={{ backgroundColor: org.color }}
onClick={() => handleOrganizationClick(org.name, org.color)}
>
<div className="name">{org.name}</div>
</div>
))}
</div>
</div>
);
};
export default Reg_Org_Filter;

View File

@ -0,0 +1,15 @@
import React from "react";
import Card_ from "../../UI/Card_/Card_";
const SelectedFilters = (props) => {
const { selectedRegion, selectedTreatyOfficialName } = props;
return (
<Card_ className="selected-filters p-2">
<h5>Selected Filter/s:</h5>
{selectedRegion && <li><i>{selectedRegion}</i></li>}
{selectedTreatyOfficialName && <li><i>{selectedTreatyOfficialName}</i></li>}
</Card_>
);
};
export default SelectedFilters;

View File

@ -0,0 +1,21 @@
import React from "react";
const Title = () => {
return (
<div className="responsive-text text-center">
<h4 className="h4">
SALW control in Africa: Organisations, treaties and instruments
</h4>
<h4 className="h4">
مراقبة الاسلحة الصغيرة و الاسلحة الخفيفة في أفريقيا: المنظمات و
المعاهدات و الأدوات
</h4>
<h4 className="h4">
Contrôle des ALPC en Afrique : Organisations, traités et instruments
</h4>
</div>
);
};
export default Title;

View File

@ -0,0 +1,238 @@
import React from "react";
import Icon1 from "../../../Icons/icon1.svg";
import Icon16 from "../../../Icons/icon16.svg";
import Icon20 from "../../../Icons/icon20.svg";
const Treaties_Filter = (props) => {
const regionalTreatiesHeadings = {
en: "Regional Treaties",
fr: "Traités régionales",
ar: "المعاهدات الأقليمية",
};
const internationalTreatiesHeadings = {
en: "International Treaties",
fr: "Traités internationales",
ar: "المعاهدات الدولية",
};
const africanGuidelinesHeadings = {
en: "African Guidelines & Instrumentss",
fr: "Directives & instruments africains",
ar: "المبادىء التوجيهية و الأدوات السياسية في افريقيا",
};
const {
international_treaties,
handleTreatiesClick,
regional_treaties,
language,
instruments,
internationalIntsruments,
africanIntsruments,
} = props;
return (
<div>
<div>
<h5>
{regionalTreatiesHeadings[language] || regionalTreatiesHeadings["en"]}
</h5>
<div className="regional-treaties">
{language === "en" && (
<div className="treaty-item">
<div className="treaty-item-name">Eligible</div>
<div className="treaty-item-name">Signed</div>
<div className="treaty-item-name">Ratified</div>
<div className="treaty-item-name"></div>
</div>
)}
{language === "fr" && (
<div className="treaty-item">
<div className="treaty-item-name">Eligible</div>
<div className="treaty-item-name">Signé</div>
<div className="treaty-item-name">Ratifié</div>
<div className="treaty-item-name"></div>
</div>
)}
{language === "ar" && (
<div className="treaty-item">
<div className="treaty-item-name">المتفق عليها</div>
<div className="treaty-item-name">موقعة</div>
<div className="treaty-item-name">مصدق عليها</div>
<div className="treaty-item-name"></div>
</div>
)}
{regional_treaties.map((treaty) => (
<div key={treaty.name} className="treaty-item">
{treaty.icon_eligible ? (
<img
src={treaty.icon_eligible}
alt={`${treaty.name}-Eligible`}
title={`${treaty.name}-Eligible`}
srcSet=""
className="icon"
onClick={() =>
handleTreatiesClick(treaty.name2, "Eligible", treaty.name)
}
/>
) : (
<div className="icon"></div>
)}
{treaty.icon_signed ? (
<img
src={treaty.icon_signed}
alt={`${treaty.name}-Signed`}
title={`${treaty.name}-Signed`}
srcSet=""
className="icon"
onClick={() =>
handleTreatiesClick(treaty.name2, "Signed", treaty.name)
}
/>
) : (
<div className="icon"></div>
)}
{treaty.icon_ratified ? (
<img
src={treaty.icon_ratified}
alt={`${treaty.name}-Ratified`}
title={`${treaty.name}-Ratified`}
srcSet=""
className="icon"
onClick={() =>
handleTreatiesClick(treaty.name2, "Ratified", treaty.name)
}
/>
) : (
<div className="icon"></div>
)}
<div className="treaty-item-name">{treaty.name}</div>
</div>
))}
</div>
<hr />
</div>
<div>
<h5>
{internationalTreatiesHeadings[language] ||
internationalTreatiesHeadings["en"]}
</h5>
{international_treaties.map((treaty) => (
<div key={treaty.name} className="treaty-item">
{treaty.icon_eligible ? (
<img
src={treaty.icon_eligible}
alt={`${treaty.name}-Eligible`}
title={`${treaty.name}-Eligible`}
srcSet=""
className="icon-2"
onClick={() =>
handleTreatiesClick(treaty.name2, "Eligible", treaty.name)
}
/>
) : (
<div className="icon"></div>
)}
{treaty.icon_signed ? (
<img
src={treaty.icon_signed}
alt={`${treaty.name}-Signed`}
title={`${treaty.name}-Signed`}
srcSet=""
className="icon-2"
onClick={() =>
handleTreatiesClick(treaty.name2, "Signed", treaty.name)
}
/>
) : (
<div className="icon"></div>
)}
{treaty.icon_ratified ? (
<img
src={treaty.icon_ratified}
alt={`${treaty.name}-Ratified`}
title={`${treaty.name}-Ratified`}
srcSet=""
className="icon-2"
onClick={() =>
handleTreatiesClick(treaty.name2, "Ratified", treaty.name)
}
/>
) : (
<div className="icon"></div>
)}
<div className="treaty-item-name">{treaty.name}</div>
</div>
))}
<hr />
</div>
<div>
{language === "en" && (
<h5>
International Guidelines & Instruments <br />
<small>(countries with recent activities only, 2014 - 2019)</small>
</h5>
)}
{language === "fr" && (
<h5>
Directives & instruments internationaux <br />
<small>(pays avec activité récente uniquement, 2014 - 2019)</small>
</h5>
)}
{language === "ar" && (
<h5>
المبادىء التوجيهية و الأدوات الدولية <br />
<small>(فقط الدول ذات النشاطات الحديثة 2014-2019)</small>
</h5>
)}
{internationalIntsruments.map((instrument) => (
<div key={instrument.name} className="instrument-item">
<img
src={instrument.icon}
alt={instrument.name}
title={instrument.name}
srcSet=""
className="icon-2"
onClick={() =>
handleTreatiesClick(
instrument.name2,
"checked",
instrument.name
)
}
/>
<div className="treaty-item-name">{instrument.name}</div>
</div>
))}
<hr />
</div>
<div>
<h5>
{africanGuidelinesHeadings[language] ||
africanGuidelinesHeadings["en"]}
</h5>
{africanIntsruments.map((instrument) => (
<div key={instrument.name} className="instrument-item">
<img
src={instrument.icon}
alt={instrument.name}
title={instrument.name}
srcSet=""
className="icon-2"
onClick={() =>
handleTreatiesClick(
instrument.name2,
"checked",
instrument.name
)
}
/>
<div className="treaty-item-name">{instrument.name}</div>
</div>
))}
</div>
</div>
);
};
export default Treaties_Filter;

View File

@ -0,0 +1,54 @@
import React, {useState} from "react";
import Card_ from "../../UI/Card_/Card_";
import Collapse from "react-bootstrap/Collapse";
const TreatyInfoBox = (props) => {
const [open, setOpen] = useState(true);
const [isHidden, setIsHidden] = useState(false);
const {
selectedRegion,
currentStatuesTreaty,
selectedTreatyOfficialName,
selectedCountriesNamesTreaties,
handleCountryChange,
} = props;
return (
<Card_ className="selected-treaty-card">
<div
onClick={() => setOpen(!open)}
aria-controls="example-collapse-text"
aria-expanded={open}
>
<h5>
{selectedRegion} members {currentStatuesTreaty}{" "}
{selectedTreatyOfficialName}
</h5>
</div>
<Collapse in={open}>
<div id="example-collapse-text">
{selectedCountriesNamesTreaties.length > 0 ? (
<ul>
{selectedCountriesNamesTreaties.map((country, index) => (
<li
onClick={handleCountryChange}
data-country={country}
key={index}
className="countries-list"
>
{country}
</li>
))}
</ul>
) : (
<p>
No {selectedRegion} members have {currentStatuesTreaty}{" "}
{selectedTreatyOfficialName}
</p>
)}
</div>
</Collapse>
</Card_>
);
};
export default TreatyInfoBox;

View File

@ -0,0 +1,26 @@
export const CountryStyle = () => {
return {
color: "black",
weight: 1,
opacity: 1,
fillColor: "#FDEDE2",
fillOpacity: 0.3,
};
};
export const CountrySelectedStyle = (color, opacity = 0.3) => {
return {
fillColor: color,
color: "black",
weight: 3,
fillOpacity: opacity,
};
};
export const CountryHighlightStyle = () => {
return {
fillColor: "yellow",
color: "black",
weight: 3,
};
};

View File

@ -0,0 +1,29 @@
import React from "react";
import Container from "react-bootstrap/esm/Container";
const MainDescription = () => {
return (
<Container className="mt-5">
<p>
<strong>SALW Guide</strong> The Interactive Guide on Small Arms and Light Weapons is an
online database that provides information on the global distribution of,
and how to identify commonly used* small arms and light weapons (SALW)
in organized violence. It is designed to build knowledge on how to
recognize different types, makes and models of commonly used SALW; to
collect data on the global and country-specific spread of these SALW;
and to describe some of their visual and technical specifications. The
guide is not an exhaustive list of all SALW that are used around the
world. The interactive Guide was developed by BICC in close cooperation
with the Bundeswehr Verification Center (BwVC) and with generous support
of the Federal Foreign Office, Germany. * This is based on information
provided by the German Bundeswehr Verification Center. The SALW Guide is
also a contribution to the UN Programme of Action (PoA) to Prevent,
Combat and Eradicate the Illicit Trade in Small Arms and Light Weapons
in All Its Aspects.
</p>
</Container>
);
};
export default MainDescription;

View File

@ -0,0 +1,43 @@
import React from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import Container from "react-bootstrap/Container";
import Nav from "react-bootstrap/Nav";
import Navbar from "react-bootstrap/Navbar";
import Home from "../../Pages/Home";
import About from "../../Pages/About";
import ControlInAfrica from "../../Pages/ControlInAfrica";
import PSSM from "../../Pages/PSSM";
const NavBarSalw = () => {
return (
<>
<Router>
<Navbar expand="lg" className="bg-body-tertiary nav-bar">
<Container fluid className="ps-5">
<Navbar.Brand className="nav-bar-title" href="#home">SALW Guide |</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Nav.Link className="nav-bar-item" href="home">Home</Nav.Link>
<Nav.Link className="nav-bar-item" href="ControlInAfrica">SALW Control in Africa</Nav.Link>
<Nav.Link className="nav-bar-item" href="pssm">PSSM</Nav.Link>
<Nav.Link className="nav-bar-item" href="about">About</Nav.Link>
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
<Routes>
<Route path="/home" element={<Home />} />
<Route path="/ControlInAfrica" element={<ControlInAfrica />} />
<Route path="/pssm" element={<PSSM />} />
<Route path="/about" element={<About />} />
</Routes>
</Router>
</>
);
};
export default NavBarSalw;

View File

@ -0,0 +1,174 @@
import React, { useState } from "react";
import Card_ from "../../UI/Card_/Card_";
import DOMPurify from "dompurify";
import parse from "html-react-parser";
import Collapse from "react-bootstrap/Collapse";
const Blurb = () => {
DOMPurify.addHook("afterSanitizeAttributes", function (node) {
// set all elements owning target to target=_blank
if ("target" in node) {
node.setAttribute("target", "_blank");
node.setAttribute("rel", "noopener");
}
});
const [footnotes, setFootnotes] = useState([
{
id: 1,
text: "Weapons are illegally given out for a short period of time in return for some money. These weapons are often used in criminal activities and then returned. This practice has been used to supplement a low salary/income.",
},
{
id: 2,
text: "UNODA Training Manual on Gender-Mainstreaming Small Arms Control, p.132, UNODA-Gender-SALW-Training-Manual®.pdf (un-arm.org)",
},
{
id: 3,
text: "Organization for Security and Co-operation in Europe (OSCE), Best Practice Guide on National Procedures for Stockpile Management and Security of Small Arms and Light Weapons, 511204.pdf (<a href='https://www.osce.org/files/f/documents/6/1/511204.pdf' target='_blank'>osce.org</a>), p.2",
},
]);
return (
<Card_ className="blurb p-3">
<MainText footnotes={footnotes} />
</Card_>
);
};
const MainText = ({ footnotes }) => {
const [open, setOpen] = useState(true);
const [isHidden, setIsHidden] = useState(true);
return (
<div>
<h3>Physical Security and Stockpile Management (PSSM)</h3>
<p>
Diverted or lost from poorly managed storage facilities, recycled
from one conflict to another or rented out
<sup>
<a href="#footnote-1">1</a>
</sup>
, small arms and light weapons (SALW) and their ammunition remain a
primary obstacle to the de-escalation of violent conflicts, national and
regional stability and peace-building efforts. Coupled with inadequate
storage practices, they further pose a serious threat to the safety and
security of nearby communities and civilian infrastructure, such as
schools and hospitals, and their easy accessibility increases the risk
that they are misused to commit armed violence (often against young men)
or acts of gender-based violence (GBV), often against women
<sup>
<a href="#footnote-2">2</a>
</sup>
.
</p>
<Collapse in={open}>
<div id="example-collapse-text">
<p>
Physical Security and Stockpile Management (PSSM) consists of the
procedures and activities that are necessary for the safe and
secure accounting, storage, transportation and handling of SALW
<sup>
<a href="#footnote-3">3</a>
</sup>
. It can therefore be viewed as a key element of practical weapons
and ammunition management, and it significantly decreases the risk
of illicit proliferation, trafficking and diversion of firearms,
ammunition, and explosives as well as reduces the risk of
Unintentional Munitions Explosions.
</p>
<p>
Responsible management of stockpiles can therefore positively impact
on efforts to reduce armed violence and contribute towards enhancing
the security of the surrounding communities as well as the security
at the local, national and regional level.
</p>
<h3>Regional PSSM Training of Trainers (ToT) processes</h3>
<p>
Since 2016, the bicc advisory team on Weapons and Ammunition
Management (WAM) has been supporting two multi-stakeholder regional
PSSM Training of Trainers (ToT) processes; one in East Africa (with
the Regional Centre on Small Arms in the Great Lakes Region, the
Horn of Africa and Bordering States, RECSA) and one in West Africa
(with the Economic Community of West African States, ECOWAS).
</p>
<p>
The aim of both processes was to support and enhance regional
ownership, strengthen PSSM capacities, establish sustainable
structures by creating a regional trainer pool whose trainers can
independently train more trainers that equally possess the necessary
regional and local knowledge, thereby decreasing a dependency on
foreign experts. The focus on regional ownership and sustainability
represents a crucial piece of the peace and security puzzle, in
alignment with SDG 16.
</p>
<p>
Based on the UN Programme of Action, and acknowledging PSSM as a key
element of WAM, the Multinational Small Arms and Ammunition Group
(MSAG) initiated a training programme on the security and stockpile
management of weapons, ammunition, and explosives for East African
states in Kenya in 2012. Participants of the ToT processes derived
from among the military, police and wildlife service sectors. Up
until March 2024, 469 participants have been trained, out of which
42 were certified as PSSM Instructors and 13 as Senior Instructors.
The map below shows their geographical distribution.
</p>
<p>
In the meantime, the need for another regional PSSM ToT process was
identified in the ECOWAS region (West Africa), which was established
in 2018 and completed in 2023. Based on the identified need for a
regional trainer pool and more accountable PSSM practices, this
process also took into account lessons learned from the East Africa
ToT process. Between 2018 and 2023, a total of 000 participants have
been trained, out of which 000 were certified as PSSM Instructors
and 000 as Senior Instructors. The map below shows their
geographical distribution.
</p>
<p>Stakeholders implementing the regional PSSM ToT trainings were:</p>
<ul>
<li>
RECSA, MSAG nations (namely the Bundeswehr Verification Centre,
the Austrian Verification Centre, Denmark, among others), IPSTC
(International Peace Support Training Centre) in Nairobi/Kenya and
bicc.
</li>
<li>ECOWAS, MSAG (the Bundeswehr Verification Centre) and bicc.</li>
</ul>
<p>
Each of these partners brings a unique skillset that complements
that of the other stakeholders.
</p>
<div>
<h4>
<hr />
</h4>
{footnotes.map((footnote) => (
<ul key={footnote.id}>
<li
className="list-unstyled"
key={footnote.id}
id={`footnote-${footnote.id}`}
>
<small>{parse(`${footnote.id}. ${footnote.text}`)}</small>
</li>
</ul>
))}
</div>
</div>
</Collapse>
{/* <a
href="#"
onClick={() => {
setOpen(!open);
setIsHidden(!isHidden);
}}
aria-controls="example-collapse-text"
aria-expanded={open}
>
{isHidden ? "Read more" : "Read less"}
</a> */}
</div>
);
};
export default Blurb;

View File

@ -0,0 +1,53 @@
import React, { useState } from "react";
import usePhotos 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(usePhotos).map((key, index) => (
<img
key={index}
src={usePhotos[key]}
alt={key}
className="thumbnail"
onClick={() => handleThumbnailClick(usePhotos[key])}
/>
))}
</div>
{selectedImage && (
<div className="modal" onClick={handleCloseModal}>
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
<span className="close" onClick={handleCloseModal}>
&times;
</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;

View 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

View File

@ -0,0 +1,22 @@
// 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)$/));
fetch('../../../data/Photos.geojson').then(response => {
return response.json();
}).then(data => {
// Work with JSON data here
console.log("Test")
console.log(data);
}).catch(err => {
// Do something for an error here
});
export default images;

View File

@ -0,0 +1,18 @@
import React from "react";
const Legend = () => {
return (
<div className="legend-container">
<div className="legend-item">
<div className="legend-recsa"></div>
<span>RECSA</span>
</div>
<div className="legend-item">
<div className="legend-ecowas"></div>
<span>ECOWAS</span>
</div>
</div>
);
};
export default Legend;

View File

@ -0,0 +1,53 @@
import React from "react";
import { Marker, Tooltip } from "react-leaflet";
import Person from "../../../Icons/person.svg";
import Person2 from "../../../Icons/person2.svg";
import Person3 from "../../../Icons/person3.svg";
const MarkerCustom = (props) => {
const { feature, pssmCountryData } = props;
return (
<Marker
position={[feature.properties.y, feature.properties.x]}
>
<Tooltip
direction="bottom"
offset={[-13, 27]}
opacity={1}
permanent
className="tooltip-custom"
>
<h5>{feature.properties.name}</h5>
<div>
<ul className="list-unstyled tooltip-text">
<li>
<img src={Person3} className="person-icon" /> Number of
participants trained:{" "}
<span className="tooltip-text-number">
{pssmCountryData["trained_participants"] || "-"}
</span>
</li>
<li>
<img src={Person2} className="person-icon" /> Number of PSSM
instractors:{" "}
<span className="tooltip-text-number">
{pssmCountryData["pssm_instractors"] || "-"}
</span>
</li>
<li>
<img src={Person} className="person-icon" /> Number of senior PSSM
instractors:{" "}
<span className="tooltip-text-number">
{pssmCountryData["senior_pssm_instractors"] || "-"}
</span>
</li>
</ul>
</div>
</Tooltip>
</Marker>
);
};
export default MarkerCustom;

View File

@ -0,0 +1,300 @@
import React, { useEffect, createRef } from "react";
import { MapContainer, GeoJSON, useMap } from "react-leaflet";
import L from "leaflet";
import Africa from "../../../Data/PSSM.geojson";
import Photos from "../../../Data/Photos.geojson";
import Africa_Outline from "../../../Data/Africa_outline.geojson";
import { fetchPSSMCountries } from '../../../api/api';
import "../../../Styles/main.scss";
import Card_ from "../../UI/Card_/Card_";
import { CountrySelectedStyle, NotPSSMCountryStyle } from "./countryStyles";
import MarkerCustom from "./MarkerCustom";
import SelectMenu from "./SelectMenu";
import Legend from "./Legend";
// Custom Zoom Control Component
const CustomZoomControl = React.memo(() => {
const map = useMap();
useEffect(() => {
const zoomControl = L.control.zoom({
position: "topright", // Change the position to bottom right
});
map.addControl(zoomControl);
// Clean up the control on component unmount
return () => {
map.removeControl(zoomControl);
};
}, [map]);
return null;
});
class PSSM extends React.Component {
constructor(props) {
super(props);
this.mapRef = createRef(); // Create a ref to store the MapContainer instance
this.state = {
africaOutline: null,
africaCountries: null,
photos: null,
//countriesNames: [],
pssmCountries: [],
pssmData: [],
recsaCountries: [],
ecowasCountries: [],
loading: true,
error: null,
selectedCountry: "",
center: [3, 15],
zoom: 3.5,
zoomSnap: 0.5,
scrollWheelZoom: false,
zoomControl: false,
};
}
componentDidMount() {
this.fetchData();
}
fetchData = async () => {
try {
const response_countries = await fetch(Africa);
const data_africa = await response_countries.json();
const response_africa_outline = await fetch(Africa_Outline);
const data_outline = await response_africa_outline.json();
const response_photos = await fetch(Photos);
const data_photos = await response_photos.json();
const data_pssm_data = await fetchPSSMCountries();
this.setState(
{
africaCountries: data_africa.features,
pssmCountries: data_africa.features.filter(
(feature) =>
data_pssm_data.find(
(item) =>
item.country === feature.properties.id && item.recsa === true
) ||
data_pssm_data.find(
(item) =>
item.country === feature.properties.id && item.ecowas === true
)
),
recsaCountries: data_africa.features.filter((feature) =>
data_pssm_data.find(
(item) =>
item.country === feature.properties.id && item.recsa === true
)
),
ecowasCountries: data_africa.features.filter((feature) =>
data_pssm_data.find(
(item) =>
item.country === feature.properties.id && item.ecowas === true
)
),
pssmData: data_pssm_data,
africaOutline: data_outline.features,
photos: data_photos.PSSM_PHOTOS,
loading: false,
},
() => {}
);
} catch (error) {
this.setState({
error: error,
loading: false,
});
}
};
onEachFeature = (feature, layer) => {
// Bind event to layer
layer.on({
click: this.onMouseClick,
});
};
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) => {
this.setState({
selectedCountriesFilter: [],
selectedCountryColor: "yellow",
});
const countryName = e.target.feature.properties.name;
if (countryName === this.state.selectedCountry) {
this.setState({ selectedCountry: "" });
return;
}
this.setState({ selectedCountry: countryName });
};
handleCountryChange = (e) => {
const countryName = e.target.value;
const { selectedCountry } = this.state;
if (countryName === selectedCountry) {
this.setState({ selectedCountry: "" });
return;
}
this.setState({ selectedCountry: countryName });
};
render() {
const {
africaCountries,
africaOutline,
pssmCountries,
pssmData,
loading,
error,
selectedCountry,
recsaCountries,
ecowasCountries,
zoomControl,
} = this.state;
if (loading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
return (
<Card_ id="map" className="map-container">
<MapContainer
ref={this.mapRef}
center={this.state.center}
zoom={this.state.zoom}
zoomSnap={this.state.zoomSnap}
style={{ width: "100%", height: "100%" }}
scrollWheelZoom={this.state.scrollWheelZoom}
zoomControl={zoomControl}
>
{africaCountries && (
<>
<GeoJSON
ref={this.geoJsonLayerRef}
onEachFeature={this.onEachFeature}
id="africa-map"
style={(feature) => {
if (
pssmData.find(
(item) =>
item.country === feature.properties.id &&
item.recsa === true
) &&
pssmData.find(
(item) =>
item.country === feature.properties.id &&
item.ecowas === true
)
) {
return CountrySelectedStyle("red");
} else if (
pssmData.find(
(item) =>
item.country === feature.properties.id &&
item.recsa === true
)
) {
return CountrySelectedStyle("#a6cee3");
} else if (
pssmData.find(
(item) =>
item.country === feature.properties.id &&
item.ecowas === true
)
) {
return CountrySelectedStyle("#ff7f00");
} else {
return NotPSSMCountryStyle();
}
}}
key="africa-map"
data={africaCountries}
/>
</>
)}
{africaOutline && (
<GeoJSON
onEachFeature={this.onEachFeature}
id="africa-outline"
data={africaOutline}
style={() => {
return {
color: "black",
weight: 3,
opacity: 1,
};
}}
/>
)}
{selectedCountry &&
pssmCountries.map((feature) => {
if (feature.properties.name === selectedCountry) {
const pssmCountryData = pssmData.find(
(item) => item.country === feature.properties.id
);
return (
<MarkerCustom
key={feature.properties.name}
feature={feature}
pssmCountryData={pssmCountryData}
></MarkerCustom>
);
}
})}
{/* <CustomZoomControl /> */}
<div className="custom-zoom-control">
<button onClick={this.zoomIn}>+</button>
<button onClick={this.zoomOut}>-</button>
<button onClick={this.resetMap}>*</button>
</div>
<SelectMenu
ecowasCountries={ecowasCountries}
recsaCountries={recsaCountries}
selectedCountry={selectedCountry}
handleCountryChange={this.handleCountryChange}
></SelectMenu>
<Legend />
</MapContainer>
</Card_>
);
}
}
export default PSSM;

View 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

View File

@ -0,0 +1,37 @@
import React from "react";
const SelectMenu = (props) => {
const {
ecowasCountries,
recsaCountries,
selectedCountry,
handleCountryChange,
} = props;
return (
<div className="country-select">
<select onChange={handleCountryChange} value={selectedCountry}>
<option value="">Select a country</option>
<option className="options-title-recsa" value="" disabled>
RECSA
</option>
{recsaCountries.map((feature, index) => (
<option className="" key={feature.properties.name} value={feature.properties.name}>
{feature.properties.name}
</option>
))}
<option className="options-title-ecowas" value="" disabled>
ECOWAS
</option>
{ecowasCountries.map((feature, index) => (
<option className="" key={feature.properties.name} value={feature.properties.name}>
{feature.properties.name}
</option>
))}
</select>
</div>
);
};
export default SelectMenu;

View File

@ -0,0 +1,36 @@
export const CountryStyle = () => {
return {
color: "black",
weight: 1,
opacity: 1,
fillColor: "#FDEDE2",
fillOpacity: 0.3,
};
};
export const CountrySelectedStyle = (color) => {
return {
fillColor: color,
color: "black",
weight: 2,
opacity: 1,
};
};
export const CountryHighlightStyle = () => {
return {
fillColor: "yellow",
color: "black",
weight: 3,
};
};
export const NotPSSMCountryStyle = () => {
return {
fillColor: "#cccccc",
color: "#e3e3e3",
weight: 1,
opacity: 1,
fillOpacity: 0,
};
};

View File

@ -0,0 +1,47 @@
import React from "react";
import Container from "react-bootstrap/esm/Container";
// Import Swiper React components
import { Swiper, SwiperSlide } from "swiper/react";
// Import Swiper styles
// Import Swiper styles
import "swiper/css";
import 'swiper/css/effect-fade';
import "swiper/css/navigation";
import "swiper/css/pagination";
import "swiper/css/scrollbar";
import classes from "./SwiperSalw.module.css";
// import required modules
import { EffectFade,Navigation, Pagination, Autoplay } from 'swiper/modules';
import weapon1 from "../../../img/weapon1.png"
import weapon2 from "../../../img/weapon2.png"
import weapon3 from "../../../img/weapon3.png"
import weapon4 from "../../../img/weapon4.png"
import weapon5 from "../../../img/weapon5.png"
const SwiperSalw = () => {
return (
<Container className="mt-5">
<Swiper
loop={true}
effect={'fade'}
autoplay={{
delay: 2500,
disableOnInteraction: false,
}}
navigation={true}
modules={[Autoplay, Navigation]}
className={`${classes.swiper}`}
>
<SwiperSlide className={classes['swiper-slide']}><img src={weapon1} alt="" /></SwiperSlide>
<SwiperSlide className={classes['swiper-slide']}><img src={weapon2} alt="" /></SwiperSlide>
<SwiperSlide className={classes['swiper-slide']}><img src={weapon3} alt="" /></SwiperSlide>
<SwiperSlide className={classes['swiper-slide']}><img src={weapon4} alt="" /></SwiperSlide>
<SwiperSlide className={classes['swiper-slide']}><img src={weapon5} alt="" /></SwiperSlide>
</Swiper>
</Container>
);
};
export default SwiperSalw;

View File

@ -0,0 +1,17 @@
.swiper {
width: 70%;
height: 70%;
display: flex;
justify-content: center;
align-items: center;
border: solid 1px #ccc;
border-radius: 15px;
background-color: #ccc;
}
.swiper-slide img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}

View File

@ -0,0 +1,47 @@
import React from "react";
import Container from "react-bootstrap/esm/Container";
import Stack from "react-bootstrap/Stack";
import Card_ from "../../UI/Card_/Card_";
import Button from "react-bootstrap/esm/Button";
import weapon1 from "../../../img/weapon1.png";
import weapon2 from "../../../img/weapon2.png";
const WeaponAmmuBut = () => {
return (
<Container className="mt-5">
<Stack direction="horizontal" gap={3} className="w-75 text-center m-auto">
<div
role="button"
className="w-100 text-center border rounded-end rounded-4 p-3"
>
<strong>Weapons</strong>
<p>
Do you know which SALW are commonly found around the world? Enter
here for an overview of some widely spread SALW including photos,
technical specifications, markings, distribution maps, and short
descriptions.
</p>
<img src={weapon1} alt="" srcset="" />
</div>
<div
role="button"
className="w-100 text-center border rounded-start rounded-4 p-3"
>
<strong>Ammunition</strong>
<p>
Do you know which SALW are commonly found around the world? Enter
here for an overview of some widely spread SALW including photos,
technical specifications, markings, distribution maps, and short
descriptions.
</p>
<img src={weapon2} alt="" srcset="" />
</div>
</Stack>
</Container>
);
};
export default WeaponAmmuBut;

View File

@ -0,0 +1,12 @@
import React from 'react';
const About = () => {
return (
<div>
<h1>About Us</h1>
<p>This is the about page content.</p>
</div>
);
};
export default About;

View File

@ -0,0 +1,27 @@
import React, { useState } from "react";
import Container from "react-bootstrap/Container";
import ControlInAfricaMap from "../Layout/ControlInAfrica/ControlInAfricaMap";
import Title from "../Layout/ControlInAfrica/Title";
import DetailsSection from "../Layout/ControlInAfrica/DetailsSection";
const ControlInAfrica = (props) => {
const [countryID, setCountryID] = useState(null);
const updateCountryID = (countryID) => {
setCountryID(countryID);
};
return (
<Container fluid className="p-5">
<Title></Title>
<ControlInAfricaMap
updateCountryID={updateCountryID}
></ControlInAfricaMap>
{countryID !== null && (
<DetailsSection countryID={countryID}></DetailsSection>
)}
</Container>
);
};
export default ControlInAfrica;

View File

@ -0,0 +1,12 @@
import React from 'react';
const Home = () => {
return (
<div>
<h1>Welcome to the Home Page!</h1>
<p>This is the home page content.</p>
</div>
);
};
export default Home;

View File

@ -0,0 +1,33 @@
import React from "react";
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 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 = () => {
return (
<Container fluid className="p-5">
<Row>
<Col sm={7}>
<Blurb></Blurb>
</Col>
<Col sm={5}>
<PSSM></PSSM>
</Col>
</Row>
<Row>
<Col sm={6}><ImpactStories className="mt-3 p-3"></ImpactStories></Col>
<Col sm={6}><PssmResources className="mt-3 p-3"></PssmResources></Col>
</Row>
<Row>
<ImageGallery className="mt-3"></ImageGallery>
</Row>
</Container>
);
};
export default Treaties;

View File

@ -0,0 +1,11 @@
import React from 'react'
import classes from './Button_.module.css'
const Button_ = props => {
return (
<button className={`${classes.card} ${props.className}`}>{props.children}</button>
)
}
export default Button_

View File

@ -0,0 +1,10 @@
import React from "react";
const Card_ = props => {
return (
<div className={`card ${props.className} `}>{props.children}</div>
);
}
export default Card_;

View File

@ -0,0 +1,5 @@
.card{
/* background-color: antiquewhite; */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
border-radius: 10px;
}

View File

@ -0,0 +1,25 @@
import React, { createContext, useContext } from 'react';
import { useQuery } from 'react-query';
import Africa from "../Data/ControlinAfrica.geojson";
const DataContext = createContext();
export const DataProvider = ({ children }) => {
const fetchData = async () => {
const response = await fetch(Africa);
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
};
const { data, error, isLoading } = useQuery('dataKey', fetchData);
return (
<DataContext.Provider value={{ data, error, isLoading }}>
{children}
</DataContext.Provider>
);
};
export const useAfricaData = () => useContext(DataContext);

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,132 @@
{
"regional_organisations": [
{ "name": "AU", "color": "#b2df8a" },
{ "name": "EAC", "color": "#33a02c" },
{ "name": "IGAD", "color": "#fb9a99" },
{ "name": "UMA", "color": "#e31a1c" },
{ "name": "COMESA", "color": "#fdbf6f" },
{ "name": "ECOWAS", "color": "#ff7f00" },
{ "name": "CEN-SAD", "color": "#cab2d6" },
{ "name": "SADC", "color": "#6a3d9a" },
{ "name": "ECCAS", "color": "#ffff99" },
{ "name": "ICGLR", "color": "#b15928" },
{ "name": "RECSA", "color": "#a6cee3" },
{ "name": "SARCOM", "color": "#1f78b4" }
],
"geographical_regions": [
{ "name": "Northern-Africa", "color": "#e3e3e3" },
{ "name": "Eastern-Africa", "color": "#e3e3e3" },
{ "name": "Southern-Africa", "color": "#e3e3e3" },
{ "name": "Western-Africa", "color": "#e3e3e3" },
{ "name": "Central-Africa", "color": "#e3e3e3" }
],
"regional_treaties": [
{
"name": "Bamako Declaration",
"name2": "BamakoDeclaration",
"icon_eligible": "Icon26",
"icon_signed": "Icon24",
"icon_ratified": "none"
},
{
"name": "Kinshasa Convention",
"name2": "KinshasaConvention",
"icon_eligible": "Icon4",
"icon_signed": "Icon6",
"icon_ratified": "Icon5"
},
{
"name": "ECOWAS Convention",
"name2": "ECOWASConvention",
"icon_eligible": "Icon2",
"icon_signed": "Icon3",
"icon_ratified": "none"
},
{
"name": "Khartoum Declaration",
"name2": "KhartoumDeclaration",
"icon_eligible": "Icon21",
"icon_signed": "Icon23",
"icon_ratified": "none"
},
{
"name": "Nairobi Protocol",
"name2": "NairobiProtocol",
"icon_eligible": "Icon22",
"icon_signed": "Icon25",
"icon_ratified": "none"
},
{
"name": "SADC Firearms Protocol",
"name2": "SADCFirearmsProtocol",
"icon_eligible": "Icon8",
"icon_signed": "Icon7",
"icon_ratified": "Icon9"
}
],
"international_treaties": [
{
"name": "Arms Trade Treaty",
"name2": "ArmsTradeTreaty",
"icon_eligible": "Icon19",
"icon_signed": "Icon17",
"icon_ratified": "Icon18"
},
{
"name": "Firearms Protocol",
"name2": "FirearmsProtocol",
"icon_eligible": "Icon12",
"icon_signed": "Icon10",
"icon_ratified": "Icon11"
},
{
"name": "Wassenaar Agreement",
"name2": "WassenaarAgreement",
"icon_eligible": "Icon15",
"icon_signed": "Icon13",
"icon_ratified": "Icon14"
}
],
"internationalIntsruments": [
{
"name2": "UNProgrammeofAction",
"name": "UN Programme of Action",
"icon": "Icon20"
},
{
"name2": "InternationalTracingInstrument",
"name": "International Tracing Instrument",
"icon": "Icon16"
}
],
"africanIntsruments": [
{
"name2": "StG-PoA",
"name": "Silencing the Guns in Africa Programme of Action",
"icon": "Icon1"
}
],
"intsruments": [
{
"name2": "UNProgrammeofAction",
"name": "UN Programme of Action",
"icon": "Icon20"
},
{
"name2": "InternationalTracingInstrument",
"name": "International Tracing Instrument",
"icon": "Icon16"
},
{
"name2": "StG-PoA",
"name": "Silencing the Guns in Africa Programme of Action",
"icon": "Icon1"
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
{
"PSSM_PHOTOS": [
{"image":"Bild1_Nikhil.jpg","copy_right":"©Nikhil Acharya"},
{"image":"Bild2_Nikhil.jpg","copy_right":"©Nikhil Acharya"},
{"image":"Storekeeper and Policewoman.jpg","copy_right":"©Nikhil Acharya"},
{"image":"Opening 2.jpg","copy_right":"©IPSTC/Kenya"},
{"image":"Group of Senior Instructors and Instructors.jpg","copy_right":"©MSAG AUT"},
{"image":"Image 1.jpg","copy_right":"©MSAG AUT"},
{"image":"bild.jpg","copy_right":""},
{"image":"1000013063.jpg","copy_right":"©Hans Lampalzer (BLMV)"},
{"image":"1000013066.jpg","copy_right":"©Hans Lampalzer (BLMV)"},
{"image":"1000013069.jpg","copy_right":"©Hans Lampalzer (BLMV)"},
{"image":"1000013072.jpg","copy_right":"©Hans Lampalzer (BLMV)"},
{"image":"1000013075.jpg","copy_right":"©Hans Lampalzer (BLMV)"},
{"image":"1000013078.jpg","copy_right":"©Hans Lampalzer (BLMV)"}
]
}

View File

@ -0,0 +1,218 @@
[
{
"id":18,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":31,
"PSSM-Instructors":2,
"PSSM-Senior-Instructors":3
},
{
"id":20,
"ECOWAS":1.0,
"RECSA":0.0,
"Trained-Participants":0,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":39,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":5,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":45,
"ECOWAS":1.0,
"RECSA":0.0,
"Trained-Participants":0,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":47,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":2,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":48,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":0,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":52,
"ECOWAS":1.0,
"RECSA":0.0,
"Trained-Participants":0,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":61,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":0,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":68,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":8,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":72,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":15,
"PSSM-Instructors":2,
"PSSM-Senior-Instructors":0
},
{
"id":83,
"ECOWAS":1.0,
"RECSA":0.0,
"Trained-Participants":0,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":85,
"ECOWAS":1.0,
"RECSA":0.0,
"Trained-Participants":0,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":87,
"ECOWAS":1.0,
"RECSA":0.0,
"Trained-Participants":0,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":88,
"ECOWAS":1.0,
"RECSA":0.0,
"Trained-Participants":0,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":118,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":138,
"PSSM-Instructors":15,
"PSSM-Senior-Instructors":4
},
{
"id":127,
"ECOWAS":1.0,
"RECSA":0.0,
"Trained-Participants":0,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":164,
"ECOWAS":1.0,
"RECSA":0.0,
"Trained-Participants":1,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":191,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":0,
"PSSM-Instructors":2,
"PSSM-Senior-Instructors":2
},
{
"id":193,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":29,
"PSSM-Instructors":2,
"PSSM-Senior-Instructors":0
},
{
"id":194,
"ECOWAS":1.0,
"RECSA":0.0,
"Trained-Participants":0,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":200,
"ECOWAS":1.0,
"RECSA":0.0,
"Trained-Participants":0,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":203,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":10,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":206,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":53,
"PSSM-Instructors":4,
"PSSM-Senior-Instructors":1
},
{
"id":214,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":12,
"PSSM-Instructors":4,
"PSSM-Senior-Instructors":1
},
{
"id":218,
"ECOWAS":1.0,
"RECSA":0.0,
"Trained-Participants":0,
"PSSM-Instructors":0,
"PSSM-Senior-Instructors":0
},
{
"id":230,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":24,
"PSSM-Instructors":5,
"PSSM-Senior-Instructors":0
},
{
"id":231,
"ECOWAS":0.0,
"RECSA":1.0,
"Trained-Participants":63,
"PSSM-Instructors":6,
"PSSM-Senior-Instructors":2
}
]

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29.36 29.36"><defs><style>.cls-1{fill:none;stroke:#000;stroke-miterlimit:10;}</style></defs><title>Element 5</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path class="cls-1" d="M4.65,4.65A14.18,14.18,0,0,1,24.71,24.71,14.18,14.18,0,0,1,4.65,4.65Z"/><line class="cls-1" x1="4.65" y1="4.65" x2="8.29" y2="8.29"/><line class="cls-1" x1="15.81" y1="15.81" x2="24.71" y2="24.71"/><path d="M14.24,13.61v.55a.75.75,0,0,1-.75.71l-1.8.06a.8.8,0,0,1-.77-.76A1.07,1.07,0,0,1,11,13.6a.19.19,0,0,1,.08.13v0a.1.1,0,0,0-.05.08.08.08,0,0,0,.07.08,1.25,1.25,0,0,0,.65,1c.05,0,.08,0,.05-.09v0h.09c.11,0,.06-.17.06-.17l-.27-.82a1.32,1.32,0,0,1,.29-.7l1.57-.17a.71.71,0,0,1,.71.71Zm6.17-4-.28-.32H20l-.18.32c-2.65,0-10.87,0-13.84,0l-.15-.37H5.59l-.17.37H4.93a.23.23,0,0,0-.25.17v1.4l0,.08,0,.4,0,.05s-.14,0-.14.28a.2.2,0,0,0,.17.21,3.2,3.2,0,0,1,.62.14c.58.17.68.78.53,1.67a4.91,4.91,0,0,1-.59,1.58c.05,0,.08,0,.08.05s-.06.07-.14.07l0,.07s.08,0,.08.06-.06.06-.14.06l0,.08s.08,0,.08.06-.07.06-.14.06L5,16.21s.07,0,.07.05-.06.06-.14.06l-.05.09s.06,0,.06.05,0,.06-.13.06l-.06.11s.06,0,.06.05-.06.06-.13.06l-.05.08s0,0,0,.05,0,0-.09.05L4.47,17s0,0,0,0,0,0-.09.05l-.06.12s0,0,0,0,0,0-.08,0l-.06.12s0,0,0,0,0,0-.07.05l-.07.12,0,0s0,0-.07.05L4,17.86s0,0,0,0,0,0,0,0L4,18.05l0,0s0,0-.05,0l-.06.16a0,0,0,0,0,0,0s0,0,0,0,0,.09-.05.13l0,0s0,0,0,0,0,.1,0,.14,0,0,0,0,0,0-.05,0l0,.13s0,0,0,0,0,0,0,0a1.13,1.13,0,0,1,0,.12l0,0,0,.08,0,.14a1.06,1.06,0,0,0,.07.64,1.37,1.37,0,0,0,.64.48h.53v0a.8.8,0,0,0-.25.45c0,.23.38.23.38.23s2.1,0,2.69,0,.54-.38.54-.38l0-.38a2.44,2.44,0,0,0,.34-.21.54.54,0,0,0,.14-.38,3.87,3.87,0,0,0,0-.45A4.55,4.55,0,0,1,9,18.53a.73.73,0,0,1,.4-.42c.1-.06.08-.13.08-.13a.67.67,0,0,1,0-.73.91.91,0,0,1,.41-.51c.21-.1.15-.18.15-.18s-.23-.27.08-.95c.19-.4.41-.52.64-.54a1.61,1.61,0,0,1,.67.23,3.6,3.6,0,0,0,.8.06l2.61-.11.08-.13,0-.15a1.88,1.88,0,0,1-.16-.89,2.46,2.46,0,0,1,.1-.88c.11-.22.55-.39.55-.39s4.34-.15,4.8-.18.47-.3.47-.3.09-.48.1-.63,0-.13,0-.13l0-.06,0,0,.09,0v-.37l0,0,0-.1a3.38,3.38,0,0,0,.07-.48A1.05,1.05,0,0,0,20.9,10a.63.63,0,0,1,0-.11c0-.06-.05,0-.05-.1a.16.16,0,0,0-.15-.16Z"/><path d="M22.94,9a.77.77,0,0,0-1.14-.18l-.06,0a.73.73,0,0,0-.16.89,2.46,2.46,0,0,1,0,2.46.73.73,0,0,0,.16.89l.06,0a.74.74,0,0,0,1.14-.18,4.12,4.12,0,0,0,.52-2A4.19,4.19,0,0,0,22.94,9Z"/><path d="M24.84,7.16A.75.75,0,0,0,23.74,7l0,0a.75.75,0,0,0-.11,1A5,5,0,0,1,24.5,11a5.14,5.14,0,0,1-.91,2.9.74.74,0,0,0,.11,1l0,0a.74.74,0,0,0,1.1-.13,6.57,6.57,0,0,0,0-7.57Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19.09 16.27"><defs><style>.cls-1{fill:none;stroke:#000;stroke-miterlimit:10;}</style></defs><title>Element 14</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path class="cls-1" d="M.5.62H7.9V3.93H3.59v2.8H7.65V10H3.59v5.76H.5Z"/><path class="cls-1" d="M9.82.83A18.27,18.27,0,0,1,13.62.5a4.88,4.88,0,0,1,3.66,1.21,5.1,5.1,0,0,1,1.31,3.64,5.81,5.81,0,0,1-1.12,3.74,4.81,4.81,0,0,1-3.84,1.59c-.3,0-.56,0-.75,0v5.14H9.82Zm3.06,6.68a3,3,0,0,0,.7.06,1.9,1.9,0,0,0,2-2.12,1.66,1.66,0,0,0-1.75-1.89,3.38,3.38,0,0,0-.91.09Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 618 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16.45 15.27"><title>Element 15</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path d="M0,.12H6.67V2.39H2.11V6.57H6.35V8.83H2.11v6.44H0Z"/><path d="M8.71.31A14.79,14.79,0,0,1,11.93,0a4.34,4.34,0,0,1,3.4,1.24,5,5,0,0,1,1.12,3.35,5.49,5.49,0,0,1-1,3.43,4.39,4.39,0,0,1-3.64,1.64,3.87,3.87,0,0,1-1-.11v5.72H8.71ZM10.8,7.37a3,3,0,0,0,1,.13c1.57,0,2.53-1,2.53-2.81S13.47,2.13,12,2.13a4.47,4.47,0,0,0-1.22.13Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 507 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14.3 15.27"><title>Element 16</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path d="M0,.12H5.7V1H.81V7H5.29v.9H.81v7.33H0Z"/><path d="M7.9.29A10.59,10.59,0,0,1,10.37,0a3.68,3.68,0,0,1,3,1.28,4.69,4.69,0,0,1,.89,3,5.19,5.19,0,0,1-.8,3A3.94,3.94,0,0,1,10.11,9a3.93,3.93,0,0,1-1.4-.18v6.48H7.9Zm.81,7.56a4.1,4.1,0,0,0,1.47.22c2.06,0,3.3-1.32,3.3-3.72S12.17.9,10.34.9a6.29,6.29,0,0,0-1.63.18Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 494 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29.24 16.42"><defs><style>.cls-1{fill:none;stroke:#000;stroke-miterlimit:10;}</style></defs><title>Element 17</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path class="cls-1" d="M2.43,15.78.57.63H3.32L3.7,6.12c.12,1.66.18,3.42.32,5.26h0c.17-1.84.41-3.51.63-5.26L5.41.63H7.53l.63,5.49c.19,1.66.36,3.33.5,5.26h0c.12-1.89.24-3.51.36-5.26L9.44.63H12L10.09,15.78H7.32l-.49-3.91c-.18-1.32-.33-3-.48-5h0c-.22,1.89-.41,3.6-.63,5l-.62,3.91Z"/><path class="cls-1" d="M13.4,12.79l-.4,3H10.44L12.88.63H16.1l2.1,15.15H15.64l-.38-3Zm1.65-2.67-.29-2.88c-.08-.85-.24-2.49-.34-3.44h0c-.12,1-.29,2.63-.4,3.44l-.34,2.88Z"/><path class="cls-1" d="M17.42,12.32a3.73,3.73,0,0,0,2,.59,1.27,1.27,0,0,0,1.43-1.35c0-1-.47-1.37-1.48-2.16a5.16,5.16,0,0,1-2.18-4.25c0-2.49,1.24-4.65,3.9-4.65A3.46,3.46,0,0,1,23,1l-.37,3a2.41,2.41,0,0,0-1.51-.52,1.23,1.23,0,0,0-1.32,1.31c0,.65.24,1.07,1.54,2a5.13,5.13,0,0,1,2.12,4.32c0,2.85-1.62,4.74-4.05,4.74a4.43,4.43,0,0,1-2.33-.59Z"/><path class="cls-1" d="M22.7,12.32a3.78,3.78,0,0,0,2,.59,1.28,1.28,0,0,0,1.44-1.35c0-1-.48-1.37-1.49-2.16a5.18,5.18,0,0,1-2.17-4.25c0-2.49,1.23-4.65,3.9-4.65a3.46,3.46,0,0,1,1.9.54L27.9,4a2.38,2.38,0,0,0-1.5-.52,1.23,1.23,0,0,0-1.32,1.31c0,.65.24,1.07,1.54,2a5.13,5.13,0,0,1,2.12,4.32c0,2.85-1.62,4.74-4,4.74a4.4,4.4,0,0,1-2.33-.59Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25.76 15.42"><title>Element 18</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path d="M2.08,15.28,0,.13H1.89l.75,6.61c.2,1.81.33,3.54.48,5.39h0c.15-1.89.41-3.54.66-5.41L4.77.13h1.5l.9,6.51c.23,1.74.45,3.44.6,5.49h.05c.16-2.07.33-3.71.51-5.45L9.07.13h1.79L8.73,15.28H6.87L6,9.24c-.21-1.5-.4-3.21-.54-5h0C5.24,6,5,7.7,4.79,9.28l-.94,6Z"/><path d="M11.59,11.34,11,15.28H9.2L11.76.13h2.13l2.39,15.15H14.49l-.61-3.94Zm2.1-1.88L13.21,6c-.14-1-.3-2.39-.42-3.45h0C12.61,3.6,12.44,5,12.3,6l-.5,3.47Z"/><path d="M15.66,12.72a3.15,3.15,0,0,0,1.78.61c1.13,0,1.74-.87,1.74-2.11a3.48,3.48,0,0,0-1.51-2.76A5.69,5.69,0,0,1,15.5,4.24C15.5,1.87,16.72,0,18.88,0A2.89,2.89,0,0,1,20.6.55l-.34,2.06a2.17,2.17,0,0,0-1.43-.52A1.65,1.65,0,0,0,17.3,3.93c0,1.17.46,1.71,1.64,2.7A5.47,5.47,0,0,1,21,11c0,2.71-1.49,4.44-3.55,4.44a3.6,3.6,0,0,1-2.09-.63Z"/><path d="M20.43,12.72a3.2,3.2,0,0,0,1.78.61c1.13,0,1.74-.87,1.74-2.11a3.45,3.45,0,0,0-1.51-2.76,5.69,5.69,0,0,1-2.17-4.22C20.27,1.87,21.5,0,23.65,0a2.89,2.89,0,0,1,1.72.55L25,2.61a2.16,2.16,0,0,0-1.42-.52,1.64,1.64,0,0,0-1.53,1.84c0,1.17.46,1.71,1.63,2.7A5.44,5.44,0,0,1,25.76,11c0,2.71-1.49,4.44-3.55,4.44a3.62,3.62,0,0,1-2.09-.63Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29.68 15.56"><title>Element 19</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path d="M2.84,15.35,0,.21H.81L2.35,8.62c.36,2,.68,3.74.88,5.3h0c.17-1.58.54-3.33,1-5.33L5.92.21h.75L8.25,8.49c.34,1.84.69,3.69.88,5.43h0c.25-1.84.58-3.5.95-5.36L11.8.21h.81L9.48,15.35H8.74L7.11,6.59C6.72,4.52,6.45,3,6.3,1.51h0c-.17,1.47-.46,3-.91,5.1L3.57,15.35Z"/><path d="M12.67,10.08l-1.28,5.27h-.8L14.33.21h.76l3.74,15.14H18l-1.29-5.27Zm3.82-.88-1.2-4.82c-.26-1.09-.41-1.94-.58-2.91h-.05c-.15,1-.33,1.88-.56,2.88L12.89,9.2Z"/><path d="M18.5,13.77a3.43,3.43,0,0,0,2.21.89c1.6,0,2.59-1.27,2.59-3.14A3.81,3.81,0,0,0,21.2,8a4.59,4.59,0,0,1-2.73-4.18C18.47,1.58,19.81,0,21.63,0a3.15,3.15,0,0,1,2.05.67l-.31.88A2.76,2.76,0,0,0,21.55.89a2.42,2.42,0,0,0-2.29,2.69c0,1.74.74,2.54,2.2,3.45a4.78,4.78,0,0,1,2.63,4.4c0,2.29-1.23,4.13-3.42,4.13a3.85,3.85,0,0,1-2.47-.92Z"/><path d="M24.09,13.77a3.46,3.46,0,0,0,2.21.89c1.6,0,2.59-1.27,2.59-3.14A3.79,3.79,0,0,0,26.79,8a4.6,4.6,0,0,1-2.72-4.18C24.07,1.58,25.41,0,27.22,0a3.15,3.15,0,0,1,2.05.67L29,1.55A2.76,2.76,0,0,0,27.14.89a2.42,2.42,0,0,0-2.29,2.69c0,1.74.75,2.54,2.21,3.45a4.77,4.77,0,0,1,2.62,4.4c0,2.29-1.23,4.13-3.42,4.13a3.81,3.81,0,0,1-2.46-.92Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18.05 15.15"><title>Element 20</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path d="M3.09,0V15.15H0V0Z"/><path d="M7.45,3.41H4.52V0h9V3.41h-3V15.15H7.45Z"/><path d="M18.05,0V15.15H15V0Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 292 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26.93 16.15"><defs><style>.cls-1{fill:none;stroke:#000;stroke-miterlimit:10;}</style></defs><title>Element 21</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path class="cls-1" d="M4.47,12.14l-.65,3.51H.62L4,.5H8.08l3.44,15.15H8.18l-.73-3.51ZM7,9.14,6.49,6.42c-.18-.86-.39-2.09-.57-3h0c-.17.9-.34,2.14-.51,3L4.88,9.14Z"/><path class="cls-1" d="M12.05,3.91H9.11V.5h9V3.91h-3V15.65H12.05Z"/><path class="cls-1" d="M20.34,3.91H17.41V.5h9V3.91h-3V15.65H20.34Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 559 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24.04 15.15"><title>Element 22</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path d="M3.16,10.87l-1,4.28H0L3.7,0H6.38l3.75,15.15H7.87l-1-4.28ZM6.48,8.78,5.57,5c-.22-.94-.42-2-.59-2.84h0C4.78,3.08,4.6,4.13,4.4,5L3.5,8.78Z"/><path d="M10.85,2.33H7.55V0h8.73V2.33H13V15.15h-2.1Z"/><path d="M18.61,2.33H15.32V0H24V2.33H20.72V15.15H18.61Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 439 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.73 15.15"><title>Element 23</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path d="M2.26,9.85.83,15.15H0L4.17,0H5L9.11,15.15H8.27L6.82,9.85ZM6.57,9,5.17,3.89c-.28-1.05-.44-1.81-.6-2.67H4.52c-.16.88-.34,1.67-.59,2.62L2.51,9Z"/><path d="M10.11.9H6.35V0h8.33V.9H10.93V15.15h-.82Z"/><path d="M17.16.9H13.4V0h8.33V.9H18V15.15h-.81Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 434 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33.76 15.4"><title>Element 24</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path d="M2.65.07V9.78c0,2,.41,2.58.89,2.58s.89-.45.89-2.58V.07H7.08V9.15C7.08,13,6,15.4,3.56,15.4.85,15.4,0,12.9,0,9.1v-9Z"/><path d="M7.23,15.22V.07H9.65l1.62,5.44c.29,1,.84,2.87,1.13,4h0c-.06-1.23-.25-4.18-.25-7V.07h2.31V15.22H12.08l-1.56-5.11C10.16,9,9.63,7,9.42,5.82h0c0,1.31.15,3.82.15,6.79v2.61Z"/><path d="M14.73.29A10.54,10.54,0,0,1,17.26,0a4,4,0,0,1,3.38,1.19,5.21,5.21,0,0,1,1.05,3.4,6.21,6.21,0,0,1-1.1,3.88,3.75,3.75,0,0,1-2.84,1.35h-.39v5.4H14.73ZM17.36,7a1.09,1.09,0,0,0,.31,0c1.06,0,1.4-1,1.4-2.14s-.38-2.11-1.23-2.11a1,1,0,0,0-.48.11Z"/><path d="M27.21,9.64c0,4.74-2.12,5.76-3.38,5.76-2.23,0-3.43-2.21-3.43-5.67C20.4,5.8,22.08,4,23.84,4,26,4,27.21,6.32,27.21,9.64ZM23,9.67c0,1.91.22,3.12.86,3.12s.72-1.55.72-3.12-.18-3.08-.76-3.08S23,8.2,23,9.67Z"/><path d="M29,12.23l-.4,3H26L28.44.07h3.22l2.1,15.15H31.2l-.38-3Zm1.66-2.68-.29-2.87c-.09-.86-.24-2.5-.35-3.44h0c-.12.94-.29,2.63-.39,3.44l-.35,2.87Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29.36 29.36"><defs><style>.cls-1{fill:none;stroke:#000;stroke-miterlimit:10;}</style></defs><title>Element 25</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path d="M25.48,9.85h-2v-2a.55.55,0,0,0-.55-.55H20.86v-2a.55.55,0,0,0-.55-.55H6.45a.55.55,0,0,0-.55.55V20.47a.55.55,0,0,0,.55.55h2v2a.55.55,0,0,0,.55.55h2.05v2a.56.56,0,0,0,.55.56h9.15a.55.55,0,0,0,.37-.16l4.68-4.22a.51.51,0,0,0,.18-.43v-11A.51.51,0,0,0,25.48,9.85ZM7,5.78H19.76V17.41l-2.85,2.44H7ZM9.6,21h7.47a.75.75,0,0,0,.36-.13l3.22-2.75a.57.57,0,0,0,.18-.43V8.38H22.3V19.27l-3.58,3.18H9.6Zm15.3.15-4.31,3.91H12.2V23.59h6.73a.57.57,0,0,0,.37-.16L23.25,20a.58.58,0,0,0,.18-.43V11H24.9Z"/><path d="M9.39,9h8A.54.54,0,0,0,18,8.47a.55.55,0,0,0-.55-.55h-8a.55.55,0,0,0-.55.55A.52.52,0,0,0,9.39,9Z"/><path d="M9.39,11.69h8a.56.56,0,0,0,0-1.11h-8a.55.55,0,0,0-.55.56A.51.51,0,0,0,9.39,11.69Z"/><path d="M17.37,13.25H15.23a.55.55,0,0,0-.55.55.55.55,0,0,0,.55.55h2.14a.55.55,0,0,0,.55-.55A.52.52,0,0,0,17.37,13.25Z"/><path d="M17.37,15.91H15.23a.55.55,0,0,0-.55.55.55.55,0,0,0,.55.55h2.14a.55.55,0,0,0,.55-.55A.52.52,0,0,0,17.37,15.91Z"/><path d="M13.3,18.42a.56.56,0,0,0,.56-.55v-4a.55.55,0,0,0-.56-.55h-4a.54.54,0,0,0-.55.55v4a.55.55,0,0,0,.55.55Zm-3.45-4h2.87v2.9H9.85Z"/><path class="cls-1" d="M24.71,4.65A14.18,14.18,0,0,0,4.65,24.71,14.18,14.18,0,0,0,24.71,4.65Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29.36 29.36"><defs><style>.cls-1{fill:none;stroke:#000;stroke-miterlimit:10;}</style></defs><title>Element 26</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path d="M21.3,23.19a2.18,2.18,0,0,1-1.51-.64.57.57,0,1,1,.8-.8h0a1.3,1.3,0,0,0,.47.27,1,1,0,0,0,1.15-1.14,1.24,1.24,0,0,0-.28-.48.57.57,0,1,1,.8-.8,2.12,2.12,0,0,1-1.43,3.59Z"/><path d="M18.08,24.26a2.22,2.22,0,0,1-1.52-.64.57.57,0,0,1,.8-.8h0a1.4,1.4,0,0,0,.48.28A1,1,0,0,0,19,22a1.4,1.4,0,0,0-.28-.48.57.57,0,1,1,.8-.8,2,2,0,0,1,0,2.95A2,2,0,0,1,18.08,24.26Z"/><path d="M14.87,25.32a2.29,2.29,0,0,1-1.51-.61h0l-1.08-1.08a.57.57,0,0,1,0-.8h0a1.25,1.25,0,0,0,.28-.47.81.81,0,0,0-.28-.88.8.8,0,0,0-.87-.27,1.34,1.34,0,0,0-.48.28.57.57,0,0,1-.8,0,.58.58,0,0,1,0-.81,2,2,0,0,1,2.94,0,2,2,0,0,1,.35,2.5l.72.71a1.26,1.26,0,0,0,.5.27.83.83,0,0,0,.86-.25.81.81,0,0,0,.24-.89,1.48,1.48,0,0,0-.26-.48.57.57,0,1,1,.84-.76,2.08,2.08,0,0,1,0,2.93A2,2,0,0,1,14.87,25.32Z"/><path d="M11.55,24.26a2,2,0,0,1-1.43-.64,1.91,1.91,0,0,1-.54-2.05,2.43,2.43,0,0,1,.54-.9.57.57,0,0,1,.8.8h0a1.34,1.34,0,0,0-.28.48.81.81,0,0,0,.28.87.81.81,0,0,0,.87.28,1.53,1.53,0,0,0,.48-.28.57.57,0,0,1,.8,0,.56.56,0,0,1,0,.8A2.18,2.18,0,0,1,11.55,24.26Z"/><path d="M23.45,21a2.22,2.22,0,0,1-1.52-.64.57.57,0,1,1,.8-.8,1.35,1.35,0,0,0,.48.27.8.8,0,0,0,.87-.27.81.81,0,0,0,.28-.87,1.4,1.4,0,0,0-.28-.48L23,17.19l0,0L17.8,12H14l-.91.91C12,14,11,14.44,10,14.25a4.22,4.22,0,0,1-2-1.37.56.56,0,0,1-.17-.4.54.54,0,0,1,.17-.4L11.2,8.86c2.05-2,6.51-1.49,7.72-1.29l1.94-1.94a.58.58,0,0,1,.8,0L27,11a.57.57,0,0,1,0,.8L25,13.86l-.92,2.76.82.83a2.44,2.44,0,0,1,.54.89,1.92,1.92,0,0,1-.54,2.06A2,2,0,0,1,23.45,21Zm-9.71-10.2H18a.59.59,0,0,1,.4.16l4.72,4.73L24,13.37a.56.56,0,0,1,.13-.22l1.75-1.75L21.26,6.83,19.51,8.58a.59.59,0,0,1-.51.16c-.05,0-5.1-1-7,.92L9.17,12.48a2.42,2.42,0,0,0,1.06.66c.55.11,1.21-.24,2-1.06L13.34,11A.59.59,0,0,1,13.74,10.84Z"/><path d="M6.18,21a2,2,0,0,1-1.44-.64,2,2,0,0,1,0-2.95L6.89,15.3a2.09,2.09,0,1,1,3,2.95.57.57,0,1,1-.8-.8H9A1.4,1.4,0,0,0,9.32,17,.81.81,0,0,0,9,16.1a.8.8,0,0,0-.87-.27,1.12,1.12,0,0,0-.48.28L5.54,18.25h0a1.29,1.29,0,0,0-.27.48.8.8,0,0,0,.27.87.81.81,0,0,0,.88.27,1.54,1.54,0,0,0,.48-.27.56.56,0,0,1,.79.8A2.18,2.18,0,0,1,6.18,21Z"/><path d="M8.33,23.19a2,2,0,0,1-1.44-.64,2,2,0,0,1-.54-2.06,2.6,2.6,0,0,1,.54-.89L9,17.45a2.36,2.36,0,0,1,1.52-.64A2.12,2.12,0,0,1,12,20.4L9.84,22.55A2.32,2.32,0,0,1,8.33,23.19ZM7.69,20.4a1.29,1.29,0,0,0-.27.48.8.8,0,0,0,.27.87.9.9,0,0,0,.64.31A1.2,1.2,0,0,0,9,21.75l2.15-2.15h0a1.4,1.4,0,0,0,.28-.48.83.83,0,0,0-.28-.87.9.9,0,0,0-.63-.31,1.25,1.25,0,0,0-.72.31L7.69,20.4Z"/><path d="M17,23.79a.58.58,0,0,1-.4-.17l-2.15-2.15a.57.57,0,0,1,.8-.8l2.15,2.15a.57.57,0,0,1,0,.8A.56.56,0,0,1,17,23.79Z"/><path d="M20.19,22.71a.55.55,0,0,1-.4-.16l-3.23-3.22a.57.57,0,0,1,0-.8.55.55,0,0,1,.8,0l3.23,3.22a.56.56,0,0,1-.4,1Z"/><path d="M22.33,20.57a.6.6,0,0,1-.4-.17l-3.22-3.22a.57.57,0,0,1,.8-.8l3.22,3.22a.55.55,0,0,1,0,.8A.56.56,0,0,1,22.33,20.57Z"/><path d="M6.22,17.34A.57.57,0,0,1,5.68,17l-1-3.1L2.59,11.8a.58.58,0,0,1-.16-.4A.56.56,0,0,1,2.6,11L8,5.63a.57.57,0,0,1,.8,0l1.94,1.94a16.83,16.83,0,0,1,4.15-.16.57.57,0,0,1,.5.63.56.56,0,0,1-.62.5,15.08,15.08,0,0,0-4.11.2.61.61,0,0,1-.51-.16L8.37,6.83,3.79,11.4l1.75,1.75a.59.59,0,0,1,.14.22L6.75,16.6a.56.56,0,0,1-.53.74Z"/><path class="cls-1" d="M24.71,4.65A14.18,14.18,0,0,0,4.65,24.71,14.18,14.18,0,0,0,24.71,4.65Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28.36 28.36"><defs><style>.cls-1{fill:#d7dfe4;}</style></defs><title>Element 27</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path class="cls-1" d="M24.21,4.15A14.18,14.18,0,0,0,4.15,24.21a14.2,14.2,0,0,0,20.06,0,14.2,14.2,0,0,0,0-20.06Z"/><path d="M24.76,9.59h-2v-2A.55.55,0,0,0,22.19,7H20.14V5a.55.55,0,0,0-.55-.55H5.73A.55.55,0,0,0,5.18,5V20.21a.55.55,0,0,0,.55.55h2v2a.55.55,0,0,0,.55.55h2v2a.55.55,0,0,0,.55.55h9.15a.49.49,0,0,0,.37-.16l4.68-4.22a.5.5,0,0,0,.18-.42v-11A.51.51,0,0,0,24.76,9.59ZM6.32,5.52H19V17.15L16.2,19.6H6.32ZM8.89,20.73h7.46a.81.81,0,0,0,.37-.12l3.21-2.76a.55.55,0,0,0,.18-.43V8.12h1.47V19L18,22.2H8.89Zm15.29.15L19.87,24.8H11.49V23.33h6.73a.55.55,0,0,0,.36-.15l4-3.49a.57.57,0,0,0,.18-.43V10.69h1.47Z"/><path d="M8.67,8.77h8a.55.55,0,0,0,.55-.55.55.55,0,0,0-.55-.55h-8a.55.55,0,0,0-.55.55A.53.53,0,0,0,8.67,8.77Z"/><path d="M8.67,11.43h8a.55.55,0,0,0,.55-.55.55.55,0,0,0-.55-.55h-8a.55.55,0,0,0-.55.55A.51.51,0,0,0,8.67,11.43Z"/><path d="M16.66,13H14.51a.55.55,0,0,0,0,1.1h2.15a.55.55,0,0,0,.55-.55A.53.53,0,0,0,16.66,13Z"/><path d="M16.66,15.65H14.51a.55.55,0,0,0,0,1.1h2.15a.55.55,0,0,0,.55-.55A.53.53,0,0,0,16.66,15.65Z"/><path d="M12.59,18.16a.55.55,0,0,0,.55-.55v-4a.55.55,0,0,0-.55-.55h-4a.54.54,0,0,0-.55.55v4a.55.55,0,0,0,.55.55Zm-3.46-4H12V17H9.13Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28.36 28.36"><defs><style>.cls-1{fill:#d7dfe4;}</style></defs><title>Element 28</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path class="cls-1" d="M24.21,4.15A14.18,14.18,0,0,0,4.15,24.21a14.2,14.2,0,0,0,20.06,0,14.2,14.2,0,0,0,0-20.06Z"/><path d="M6.33,3.29A2.09,2.09,0,0,0,4.25,5.37v1a.38.38,0,0,0,.38.37H18.24a.37.37,0,0,0,.37-.37v-1a1.33,1.33,0,0,1,2.65,0V21.24a2.08,2.08,0,0,0,4.16,0,.38.38,0,0,0-.38-.38H22.77a.38.38,0,1,0,0,.76H24.6A1.32,1.32,0,0,1,22,21.24V5.37a2.09,2.09,0,0,0-2.08-2.08Zm0,.76h12a2,2,0,0,0-.48,1.32v.56H5V5.37A1.31,1.31,0,0,1,6.33,4.05Z"/><path d="M6.94,6.32V21.24A2.08,2.08,0,0,0,9,23.32h2.41v-.75H9A1.32,1.32,0,0,1,7.7,21.24V6.32Z"/><path d="M16.16,8.59a.37.37,0,0,0-.38.37.38.38,0,0,0,.37.38H19A.37.37,0,0,0,19.37,9,.37.37,0,0,0,19,8.59H16.16Z"/><path d="M9.93,8.59A.37.37,0,0,0,9.55,9a.38.38,0,0,0,.37.38h1.14A.37.37,0,0,0,11.44,9a.38.38,0,0,0-.37-.38H9.93Z"/><path d="M12.39,8.59a.38.38,0,1,0,0,.75h2.45a.38.38,0,1,0,0-.75H12.39Z"/><path d="M13.9,11.61a.39.39,0,0,0-.39.37.4.4,0,0,0,.38.39H19a.38.38,0,0,0,.38-.38.37.37,0,0,0-.37-.38H13.9Z"/><path d="M9.93,11.61a.37.37,0,0,0-.38.37.38.38,0,0,0,.37.39h2.64A.4.4,0,0,0,13,12a.38.38,0,0,0-.38-.38H9.93Z"/><path d="M14.46,14.6a3.59,3.59,0,1,0,3.59,3.59A3.6,3.6,0,0,0,14.46,14.6Zm0,.76a2.84,2.84,0,1,1-2.84,2.83A2.82,2.82,0,0,1,14.46,15.36Z"/><path d="M12.23,20.68v4.91a.38.38,0,0,0,.38.38.35.35,0,0,0,.19-.06l1.7-1,1.69,1a.38.38,0,0,0,.52-.13.32.32,0,0,0,.05-.19V20.68H16v4.24l-1.32-.79a.39.39,0,0,0-.39,0L13,24.92V20.68Z"/><path d="M17.48,22.57v.76h5.86v-.76Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28.36 28.36"><defs><style>.cls-1{fill:#d7dfe4;}</style></defs><title>Element 29</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path class="cls-1" d="M24.21,4.15A14.18,14.18,0,0,0,4.15,24.21a14.2,14.2,0,0,0,20.06,0,14.2,14.2,0,0,0,0-20.06Z"/><path d="M21.23,23.05a2.24,2.24,0,0,1-1.51-.64.57.57,0,1,1,.8-.8h0a1.29,1.29,0,0,0,.48.27,1,1,0,0,0,1.14-1.14,1.28,1.28,0,0,0-.28-.49.55.55,0,0,1,0-.79.57.57,0,0,1,.8,0,2.12,2.12,0,0,1-1.44,3.59Z"/><path d="M18,24.12a2.18,2.18,0,0,1-1.51-.64.55.55,0,0,1,0-.8.57.57,0,0,1,.8,0h0a1.42,1.42,0,0,0,.47.28.81.81,0,0,0,.87-.28.79.79,0,0,0,.28-.87,1.24,1.24,0,0,0-.28-.48.57.57,0,1,1,.8-.8,2,2,0,0,1,0,2.95A2,2,0,0,1,18,24.12Z"/><path d="M14.81,25.17a2.33,2.33,0,0,1-1.52-.6h0L12.2,23.48a.57.57,0,0,1,0-.8h0a1.29,1.29,0,0,0,.27-.48.8.8,0,0,0-.27-.87.8.8,0,0,0-.87-.27,1.12,1.12,0,0,0-.48.28.56.56,0,0,1-.8,0,.57.57,0,0,1,0-.8,2,2,0,0,1,2.95,0,2,2,0,0,1,.34,2.5l.72.71a1.4,1.4,0,0,0,.5.27.82.82,0,0,0,.86-.25.84.84,0,0,0,.25-.89,1.29,1.29,0,0,0-.27-.48.57.57,0,1,1,.84-.76,2.08,2.08,0,0,1,0,2.93A1.94,1.94,0,0,1,14.81,25.17Z"/><path d="M11.49,24.12a2,2,0,0,1-1.44-.64,1.92,1.92,0,0,1-.54-2.05,2.43,2.43,0,0,1,.54-.9.57.57,0,0,1,.8.8h0a1.4,1.4,0,0,0-.28.48.81.81,0,0,0,.28.87.81.81,0,0,0,.87.28,1.4,1.4,0,0,0,.48-.28.57.57,0,1,1,.8.8A2.22,2.22,0,0,1,11.49,24.12Z"/><path d="M23.38,20.9a2.18,2.18,0,0,1-1.51-.64.57.57,0,0,1,0-.8.56.56,0,0,1,.79,0,1.35,1.35,0,0,0,.48.27.81.81,0,0,0,.88-.27.8.8,0,0,0,.27-.87,1.24,1.24,0,0,0-.28-.48L23,17h0l-5.19-5.2H13.91l-.91.91c-1.11,1.11-2.11,1.55-3.06,1.37a4.22,4.22,0,0,1-2-1.37.56.56,0,0,1-.17-.4.54.54,0,0,1,.17-.4s1.1-1.1,3.23-3.22,6.51-1.49,7.72-1.29l1.94-1.94a.55.55,0,0,1,.4-.16.54.54,0,0,1,.4.16L27,10.86a.57.57,0,0,1,0,.8l-2.06,2.06L24,16.48l.83.83a2.78,2.78,0,0,1,.54.89,2,2,0,0,1-.54,2.06A2,2,0,0,1,23.38,20.9ZM13.67,10.7H18a.59.59,0,0,1,.4.16l4.72,4.73.79-2.36A.52.52,0,0,1,24,13l1.75-1.75L21.19,6.69,19.44,8.44a.56.56,0,0,1-.51.15c-.05,0-5.09-1-7,.93L9.11,12.33a2.28,2.28,0,0,0,1.05.67c.55.11,1.22-.24,2-1.06l1.07-1.08A.59.59,0,0,1,13.67,10.7Z"/><path d="M6.11,20.9a2,2,0,0,1-1.43-.64,2,2,0,0,1,0-3l2.15-2.15a2,2,0,0,1,2.94,0,2,2,0,0,1,0,2.95.57.57,0,1,1-.8-.8H9a1.24,1.24,0,0,0,.28-.48A.81.81,0,0,0,9,16a.8.8,0,0,0-.87-.27,1.4,1.4,0,0,0-.48.27L5.48,18.11h0a1.24,1.24,0,0,0-.28.48.81.81,0,0,0,.28.87.8.8,0,0,0,.87.27,1.29,1.29,0,0,0,.48-.27.56.56,0,0,1,.8,0,.57.57,0,0,1,0,.8A2.22,2.22,0,0,1,6.11,20.9Z"/><path d="M8.26,23.05a2,2,0,0,1-1.43-.64,1.93,1.93,0,0,1-.54-2.06,2.44,2.44,0,0,1,.54-.89L9,17.31a2.31,2.31,0,0,1,1.52-.64,2.12,2.12,0,0,1,1.43,3.59L9.77,22.41A2.29,2.29,0,0,1,8.26,23.05Zm-.63-2.79a1.24,1.24,0,0,0-.28.48.79.79,0,0,0,.28.87.88.88,0,0,0,.63.31A1.2,1.2,0,0,0,9,21.61l2.15-2.15h0A1.4,1.4,0,0,0,11.4,19a.81.81,0,0,0-.28-.87.88.88,0,0,0-.63-.31,1.29,1.29,0,0,0-.72.31L7.63,20.26Z"/><path d="M16.9,23.65a.56.56,0,0,1-.4-.17l-2.15-2.15a.57.57,0,0,1,.8-.8l2.15,2.15a.57.57,0,0,1,0,.8A.6.6,0,0,1,16.9,23.65Z"/><path d="M20.12,22.57a.55.55,0,0,1-.4-.16L16.5,19.18a.55.55,0,0,1,0-.8.57.57,0,0,1,.8,0l3.22,3.23a.56.56,0,0,1-.4,1Z"/><path d="M22.27,20.42a.55.55,0,0,1-.4-.16L18.64,17a.57.57,0,0,1,.8-.8l3.23,3.22a.56.56,0,0,1-.4,1Z"/><path d="M6.15,17.2a.57.57,0,0,1-.54-.39l-1-3.09L2.53,11.66a.54.54,0,0,1-.17-.4.56.56,0,0,1,.17-.4L7.91,5.49a.57.57,0,0,1,.8,0l1.94,1.94a16.74,16.74,0,0,1,4.14-.16.56.56,0,0,1,.5.62.57.57,0,0,1-.62.51,15.68,15.68,0,0,0-4.1.19.58.58,0,0,1-.52-.15L8.3,6.69,3.73,11.26,5.48,13a.5.5,0,0,1,.13.22l1.08,3.23a.56.56,0,0,1-.36.71A.57.57,0,0,1,6.15,17.2Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29.36 29.36"><defs><style>.cls-1{fill:none;stroke:#000;stroke-miterlimit:10;}</style></defs><title>Element 30</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path class="cls-1" d="M24.71,4.65A14.18,14.18,0,0,0,4.65,24.71,14.18,14.18,0,0,0,24.71,4.65Z"/><path d="M6.7,4.12A2.08,2.08,0,0,0,4.62,6.2v.94A.38.38,0,0,0,5,7.52H18.6A.38.38,0,0,0,19,7.14V6.2a1.33,1.33,0,1,1,2.65,0V22.07a2.08,2.08,0,1,0,4.16,0,.39.39,0,0,0-.38-.38H23.14a.38.38,0,1,0,0,.76H25a1.32,1.32,0,0,1-2.59-.38V6.2a2.08,2.08,0,0,0-2.07-2.08Zm0,.75h12a2,2,0,0,0-.48,1.32v.57H5.38V6.19A1.32,1.32,0,0,1,6.7,4.87Z"/><path d="M7.31,7.14V22.07a2.09,2.09,0,0,0,2.08,2.08H11.8v-.76H9.39a1.31,1.31,0,0,1-1.32-1.32V7.14Z"/><path d="M16.53,9.41a.38.38,0,0,0,0,.76h2.83a.38.38,0,1,0,0-.76H16.53Z"/><path d="M10.3,9.41a.38.38,0,0,0,0,.76h1.13a.38.38,0,1,0,0-.76H10.3Z"/><path d="M12.75,9.41a.38.38,0,0,0,0,.76H15.2a.38.38,0,0,0,.38-.37.39.39,0,0,0-.37-.39H12.75Z"/><path d="M14.26,12.44a.37.37,0,0,0-.38.37.38.38,0,0,0,.38.38h5.09a.39.39,0,0,0,.39-.37.38.38,0,0,0-.38-.38h-5.1Z"/><path d="M10.3,12.44a.38.38,0,1,0,0,.75h2.64a.37.37,0,0,0,.38-.37.37.37,0,0,0-.37-.38H10.3Z"/><path d="M14.83,15.43A3.59,3.59,0,1,0,18.42,19,3.59,3.59,0,0,0,14.83,15.43Zm0,.76A2.83,2.83,0,1,1,12,19,2.82,2.82,0,0,1,14.83,16.19Z"/><path d="M12.59,21.5v4.91a.38.38,0,0,0,.38.38.46.46,0,0,0,.2-.05l1.69-1,1.7,1a.38.38,0,0,0,.52-.13.46.46,0,0,0,.05-.2V21.5h-.76v4.25L15.06,25a.35.35,0,0,0-.39,0l-1.32.79V21.5Z"/><path d="M17.85,23.4v.75h5.86V23.4Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28.36 28.36"><defs><style>.cls-1{fill:#d7dfe4;}.cls-2{fill:none;stroke:#000;stroke-miterlimit:10;}</style></defs><title>Element 11</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path class="cls-1" d="M4.15,4.15A14.18,14.18,0,0,1,24.21,24.21,14.18,14.18,0,0,1,4.15,4.15Z"/><path d="M17.31,13.65v.7a1,1,0,0,1-1,.92L14,15.34a1,1,0,0,1-1-1,1.51,1.51,0,0,1,.1-.75.28.28,0,0,1,.11.18v0a.1.1,0,0,0-.07.1.11.11,0,0,0,.09.1,1.64,1.64,0,0,0,.84,1.24c.06,0,.11-.06.07-.12l0,0a.24.24,0,0,0,.12,0c.13,0,.08-.22.08-.22L14,13.85a1.62,1.62,0,0,1,.39-.9l2-.22a.92.92,0,0,1,.92.92Zm8-5.14L24.9,8.1h-.15l-.22.41H6.69L6.5,8H6.16L6,8.51H5.32A.32.32,0,0,0,5,8.74v1.8l.06.11,0,.51,0,.06s-.18,0-.18.37a.24.24,0,0,0,.21.26,4,4,0,0,1,.81.19c.74.21.87,1,.67,2.14a6.24,6.24,0,0,1-.75,2c.06,0,.1,0,.1.07s-.08.08-.18.08l-.06.1c.06,0,.1,0,.1.07s-.08.09-.18.09l-.07.09c.06,0,.1.05.1.08s-.08.08-.18.08L5.37,17s.08,0,.08.07-.07.07-.17.07l-.07.12s.08,0,.08.07-.07.07-.16.07L5,17.54s.08,0,.08.06-.07.08-.16.08l-.06.1s0,0,0,.06-.06.06-.13.07l-.09.16s0,0,0,0,0,.06-.12.06l-.08.16s0,0,0,0,0,.05-.1.06l-.08.16,0,0s0,.05-.1.06l-.08.16s0,0,0,0,0,.05-.09.06l-.08.16a.05.05,0,0,1,0,0s0,0-.07.05l-.08.17a0,0,0,0,1,0,0s0,0-.06.05l-.09.2,0,0s0,0-.05,0l-.06.18s0,0,0,0,0,0,0,0l-.06.18s0,0,0,0,0,0-.06,0,0,.12,0,.16a.05.05,0,0,1,0,0s0,0,0,0l0,.14,0,.06,0,.1,0,.18a1.4,1.4,0,0,0,.09.83,1.81,1.81,0,0,0,.83.61H5.2v0a1,1,0,0,0-.31.58c0,.3.48.29.48.29s2.71,0,3.47,0,.69-.48.69-.48l.06-.5a3.23,3.23,0,0,0,.45-.26.78.78,0,0,0,.18-.5c0-.18,0-.45,0-.57a6.11,6.11,0,0,1,.36-1,1,1,0,0,1,.51-.54c.13-.08.11-.17.11-.17a.83.83,0,0,1,0-.93,1.21,1.21,0,0,1,.53-.67c.27-.12.19-.22.19-.22s-.3-.35.1-1.23c.25-.52.53-.67.83-.69a1.94,1.94,0,0,1,.86.29,4.43,4.43,0,0,0,1,.07l3.36-.14.11-.16-.08-.19A2.49,2.49,0,0,1,18,14.25a3.16,3.16,0,0,1,.12-1.13c.14-.29.71-.51.71-.51s5.59-.19,6.19-.23.6-.39.6-.39.11-.61.13-.8,0-.18,0-.18l0-.07,0,0,.12,0v-.48l0,0,0-.12A3.55,3.55,0,0,0,26,9.61,1.26,1.26,0,0,0,25.89,9a.49.49,0,0,1,0-.14c0-.07-.06,0-.06-.13a.2.2,0,0,0-.2-.2Z"/><line class="cls-2" x1="4.3" y1="4.01" x2="7.64" y2="7.35"/><line class="cls-2" x1="17.18" y1="16.88" x2="24.35" y2="24.06"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29.36 29.36"><defs><style>.cls-1,.cls-2{fill:none;stroke:#000;stroke-miterlimit:10;}.cls-2{stroke-width:0.75px;}</style></defs><title>Element 12</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path class="cls-1" d="M4.65,4.65A14.18,14.18,0,0,1,24.71,24.71,14.18,14.18,0,0,1,4.65,4.65Z"/><path class="cls-2" d="M17.81,14.15v.7a1,1,0,0,1-1,.92l-2.32.07a1,1,0,0,1-1-1,1.51,1.51,0,0,1,.1-.75.28.28,0,0,1,.11.18v0a.1.1,0,0,0-.07.1.11.11,0,0,0,.09.1,1.64,1.64,0,0,0,.84,1.24c.06,0,.11-.06.07-.12l0,0a.24.24,0,0,0,.12,0c.13,0,.08-.22.08-.22l-.36-1.05a1.62,1.62,0,0,1,.39-.9l2-.22a.92.92,0,0,1,.92.92Zm8-5.14L25.4,8.6h-.15L25,9H7.19L7,8.53H6.66L6.45,9H5.82a.32.32,0,0,0-.33.23V11l.06.11,0,.51,0,.06s-.18,0-.18.37a.24.24,0,0,0,.21.26,4,4,0,0,1,.81.19c.74.21.87,1,.67,2.14a6.24,6.24,0,0,1-.75,2c.06,0,.1,0,.1.07s-.08.08-.18.08l-.06.1c.06,0,.1,0,.1.07s-.08.09-.18.09L6,17.22c.06,0,.1.05.1.08s-.08.08-.18.08l-.07.11s.08,0,.08.07-.07.07-.17.07l-.07.12s.08,0,.08.07-.07.07-.16.07L5.54,18s.08,0,.08.06-.07.08-.16.08l-.06.1s0,0,0,.06-.06.06-.13.07l-.09.16s0,0,0,0,0,.06-.12.06l-.08.16s0,0,0,0,0,.05-.1.06l-.08.16,0,0s0,.05-.1.06l-.08.16s0,0,0,0,0,.05-.09.06l-.08.16a.05.05,0,0,1,0,0s0,0-.07.05l-.08.17a0,0,0,0,1,0,0s0,0-.06.05l-.09.2,0,0s0,0,0,0l-.06.18s0,0,0,0,0,0-.05,0l-.06.18s0,0,0,0,0,0-.06,0,0,.12,0,.16a.05.05,0,0,1,0,0s0,0,0,0l0,.14,0,.06,0,.1,0,.18a1.4,1.4,0,0,0,.09.83,1.81,1.81,0,0,0,.83.61H5.7v0a1,1,0,0,0-.31.58c0,.3.48.29.48.29s2.71,0,3.47,0,.69-.48.69-.48l.06-.5a3.23,3.23,0,0,0,.45-.26.78.78,0,0,0,.18-.5c0-.18,0-.45,0-.57a6.11,6.11,0,0,1,.36-1,1,1,0,0,1,.51-.54c.13-.08.11-.17.11-.17a.83.83,0,0,1,0-.93,1.21,1.21,0,0,1,.53-.67c.27-.12.19-.22.19-.22s-.3-.35.1-1.23c.25-.52.53-.67.83-.69a1.94,1.94,0,0,1,.86.29,4.43,4.43,0,0,0,1,.07l3.36-.14.11-.16-.08-.19a2.49,2.49,0,0,1-.19-1.15,3.16,3.16,0,0,1,.12-1.13c.14-.29.71-.51.71-.51s5.59-.19,6.19-.23.6-.39.6-.39.11-.61.13-.8,0-.18,0-.18l0-.07,0,0,.12,0v-.48l0,0,0-.12a3.55,3.55,0,0,0,.09-.62,1.26,1.26,0,0,0-.14-.63.49.49,0,0,1,0-.14c0-.07-.06,0-.06-.13a.2.2,0,0,0-.2-.2Z"/><path class="cls-1" d="M4.65,4.65A14.18,14.18,0,0,1,24.71,24.71,14.18,14.18,0,0,1,4.65,4.65Zm0,0L7.22,7.22M18.14,18.14l6.57,6.57"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 28.36 28.36"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:none;stroke:#fff;stroke-miterlimit:10;}</style></defs><title>Element 13</title><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><path d="M4.15,4.15A14.18,14.18,0,0,1,24.21,24.21,14.18,14.18,0,0,1,4.15,4.15Z"/><path class="cls-1" d="M17.31,13.65v.7a1,1,0,0,1-1,.92L14,15.34a1,1,0,0,1-1-1,1.51,1.51,0,0,1,.1-.75.28.28,0,0,1,.11.18v0a.1.1,0,0,0-.07.1.11.11,0,0,0,.09.1,1.64,1.64,0,0,0,.84,1.24c.06,0,.11-.06.07-.12l0,0a.24.24,0,0,0,.12,0c.13,0,.08-.22.08-.22L14,13.85a1.62,1.62,0,0,1,.39-.9l2-.22a.92.92,0,0,1,.92.92Zm8-5.14L24.9,8.1h-.15l-.22.41H6.69L6.5,8H6.16L6,8.51H5.32A.32.32,0,0,0,5,8.74v1.8l.06.11,0,.51,0,.06s-.18,0-.18.37a.24.24,0,0,0,.21.26,4,4,0,0,1,.81.19c.74.21.87,1,.67,2.14a6.24,6.24,0,0,1-.75,2c.06,0,.1,0,.1.07s-.08.08-.18.08l-.06.1c.06,0,.1,0,.1.07s-.08.09-.18.09l-.07.09c.06,0,.1.05.1.08s-.08.08-.18.08L5.37,17s.08,0,.08.07-.07.07-.17.07l-.07.12s.08,0,.08.07-.07.07-.16.07L5,17.54s.08,0,.08.06-.07.08-.16.08l-.06.1s0,0,0,.06-.06.06-.13.07l-.09.16s0,0,0,0,0,.06-.12.06l-.08.16s0,0,0,0,0,.05-.1.06l-.08.16,0,0s0,.05-.1.06l-.08.16s0,0,0,0,0,.05-.09.06l-.08.16a.05.05,0,0,1,0,0s0,0-.07.05l-.08.17a0,0,0,0,1,0,0s0,0-.06.05l-.09.2,0,0s0,0-.05,0l-.06.18s0,0,0,0,0,0,0,0l-.06.18s0,0,0,0,0,0-.06,0,0,.12,0,.16a.05.05,0,0,1,0,0s0,0,0,0l0,.14,0,.06,0,.1,0,.18a1.4,1.4,0,0,0,.09.83,1.81,1.81,0,0,0,.83.61H5.2v0a1,1,0,0,0-.31.58c0,.3.48.29.48.29s2.71,0,3.47,0,.69-.48.69-.48l.06-.5a3.23,3.23,0,0,0,.45-.26.78.78,0,0,0,.18-.5c0-.18,0-.45,0-.57a6.11,6.11,0,0,1,.36-1,1,1,0,0,1,.51-.54c.13-.08.11-.17.11-.17a.83.83,0,0,1,0-.93,1.21,1.21,0,0,1,.53-.67c.27-.12.19-.22.19-.22s-.3-.35.1-1.23c.25-.52.53-.67.83-.69a1.94,1.94,0,0,1,.86.29,4.43,4.43,0,0,0,1,.07l3.36-.14.11-.16-.08-.19A2.49,2.49,0,0,1,18,14.25a3.16,3.16,0,0,1,.12-1.13c.14-.29.71-.51.71-.51s5.59-.19,6.19-.23.6-.39.6-.39.11-.61.13-.8,0-.18,0-.18l0-.07,0,0,.12,0v-.48l0,0,0-.12A3.55,3.55,0,0,0,26,9.61,1.26,1.26,0,0,0,25.89,9a.49.49,0,0,1,0-.14c0-.07-.06,0-.06-.13a.2.2,0,0,0-.2-.2Z"/><line class="cls-2" x1="16.79" y1="16.79" x2="24.21" y2="24.21"/><line class="cls-2" x1="4.15" y1="4.15" x2="7.44" y2="7.44"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
<desc>Created with Fabric.js 5.2.4</desc>
<defs>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="transparent"></rect>
<g transform="matrix(1 0 0 1 540 540)" id="92f8c780-682d-410e-9305-55f6c76b821a" >
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
</g>
<g transform="matrix(1 0 0 1 540 540)" id="2902fc72-5f87-4d9a-a213-49b43b827461" >
</g>
<g transform="matrix(1 0 0 1 174.64 508.98)" >
<g style="" vector-effect="non-scaling-stroke" >
<g transform="matrix(33.33 0 0 33.33 -0.01 1.63)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-12, -12.05)" d="M 13.9 2.999 C 13.900404510128258 3.767569137253463 13.437740927005041 4.4606849303964715 12.727791698439338 4.755083937232331 C 12.017842469873635 5.04948294406819 11.200454630665819 4.88717393579122 10.656851071891348 4.343856484152948 C 10.113247513116876 3.800539032514675 9.950508209994716 2.9832367548523684 10.244533420214 2.273132637048167 C 10.538558630433283 1.5630285192439657 11.231430756296502 1.1000001064500415 12 1.1 C 13.048950624407942 1.09999985471597 13.899447920724006 1.9500495208760782 13.9 2.9990000000000006 z M 13.544 6 L 10.456 6 C 9.604684814488484 5.999811949956359 8.862518492883558 6.579113995431316 8.655999999999999 7.405000000000001 L 6.993999999999999 14.057 C 6.949087749408432 14.259377888455008 7.00082563788415 14.471133674859198 7.133999999999999 14.63 C 7.29552492159201 14.833465444933692 7.539274387351227 14.954423826438266 7.798999999999999 14.96 C 8.086057992331412 14.955557715508808 8.34287529667128 14.780544391724366 8.451999999999998 14.515 L 10 9.1 L 10 13 L 9.078 22.219 C 9.057924474646427 22.41874832997887 9.123349536101328 22.61765922173752 9.258078407025312 22.76648984152766 C 9.392807277949297 22.915320461317805 9.584245430761463 23.000158042462385 9.785 23 L 9.859 23 C 10.19101964547464 22.999898168622497 10.475889150458729 22.763347237492642 10.537 22.437 L 12 14.583 L 13.463000000000001 22.437 C 13.524110849541275 22.763347237492642 13.808980354525362 22.999898168622497 14.141000000000002 23 L 14.215000000000002 23 C 14.415754569238539 23.000158042462385 14.607192722050703 22.915320461317805 14.74192159297469 22.76648984152766 C 14.876650463898674 22.61765922173752 14.942075525353575 22.41874832997887 14.922000000000002 22.219 L 14 13 L 14 9.1 L 15.548 14.515 C 15.65743368223532 14.780152409969652 15.914184251847452 14.954727069859064 16.201 14.959000000000001 C 16.460559067140714 14.953667969304108 16.704279363027823 14.83309055975996 16.866 14.63 C 16.99917436211585 14.471133674859198 17.05091225059157 14.259377888455008 17.006 14.057 L 15.344000000000001 7.405 C 15.137481507116442 6.579113995431316 14.395315185511514 5.999811949956358 13.544 6 z" stroke-linecap="round" />
</g>
<g transform="matrix(33.33 0 0 33.33 -0.04 -0.04)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: none; fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-12, -12)" d="M 0 0 L 24 0 L 24 24 L 0 24 z" stroke-linecap="round" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
<desc>Created with Fabric.js 5.2.4</desc>
<defs>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="transparent"></rect>
<g transform="matrix(1 0 0 1 540 540)" id="92f8c780-682d-410e-9305-55f6c76b821a" >
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
</g>
<g transform="matrix(1 0 0 1 540 540)" id="2902fc72-5f87-4d9a-a213-49b43b827461" >
</g>
<g transform="matrix(1 0 0 1 174.64 508.98)" >
<g style="" vector-effect="non-scaling-stroke" >
<g transform="matrix(33.33 0 0 33.33 -0.01 1.63)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-12, -12.05)" d="M 13.9 2.999 C 13.900404510128258 3.767569137253463 13.437740927005041 4.4606849303964715 12.727791698439338 4.755083937232331 C 12.017842469873635 5.04948294406819 11.200454630665819 4.88717393579122 10.656851071891348 4.343856484152948 C 10.113247513116876 3.800539032514675 9.950508209994716 2.9832367548523684 10.244533420214 2.273132637048167 C 10.538558630433283 1.5630285192439657 11.231430756296502 1.1000001064500415 12 1.1 C 13.048950624407942 1.09999985471597 13.899447920724006 1.9500495208760782 13.9 2.9990000000000006 z M 13.544 6 L 10.456 6 C 9.604684814488484 5.999811949956359 8.862518492883558 6.579113995431316 8.655999999999999 7.405000000000001 L 6.993999999999999 14.057 C 6.949087749408432 14.259377888455008 7.00082563788415 14.471133674859198 7.133999999999999 14.63 C 7.29552492159201 14.833465444933692 7.539274387351227 14.954423826438266 7.798999999999999 14.96 C 8.086057992331412 14.955557715508808 8.34287529667128 14.780544391724366 8.451999999999998 14.515 L 10 9.1 L 10 13 L 9.078 22.219 C 9.057924474646427 22.41874832997887 9.123349536101328 22.61765922173752 9.258078407025312 22.76648984152766 C 9.392807277949297 22.915320461317805 9.584245430761463 23.000158042462385 9.785 23 L 9.859 23 C 10.19101964547464 22.999898168622497 10.475889150458729 22.763347237492642 10.537 22.437 L 12 14.583 L 13.463000000000001 22.437 C 13.524110849541275 22.763347237492642 13.808980354525362 22.999898168622497 14.141000000000002 23 L 14.215000000000002 23 C 14.415754569238539 23.000158042462385 14.607192722050703 22.915320461317805 14.74192159297469 22.76648984152766 C 14.876650463898674 22.61765922173752 14.942075525353575 22.41874832997887 14.922000000000002 22.219 L 14 13 L 14 9.1 L 15.548 14.515 C 15.65743368223532 14.780152409969652 15.914184251847452 14.954727069859064 16.201 14.959000000000001 C 16.460559067140714 14.953667969304108 16.704279363027823 14.83309055975996 16.866 14.63 C 16.99917436211585 14.471133674859198 17.05091225059157 14.259377888455008 17.006 14.057 L 15.344000000000001 7.405 C 15.137481507116442 6.579113995431316 14.395315185511514 5.999811949956358 13.544 6 z" stroke-linecap="round" />
</g>
<g transform="matrix(33.33 0 0 33.33 -0.04 -0.04)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: none; fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-12, -12)" d="M 0 0 L 24 0 L 24 24 L 0 24 z" stroke-linecap="round" />
</g>
</g>
</g>
<g transform="matrix(1 0 0 1 508.64 510.94)" >
<g style="" vector-effect="non-scaling-stroke" >
<g transform="matrix(33.33 0 0 33.33 -0.01 1.63)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-12, -12.05)" d="M 13.9 2.999 C 13.900404510128258 3.767569137253463 13.437740927005041 4.4606849303964715 12.727791698439338 4.755083937232331 C 12.017842469873635 5.04948294406819 11.200454630665819 4.88717393579122 10.656851071891348 4.343856484152948 C 10.113247513116876 3.800539032514675 9.950508209994716 2.9832367548523684 10.244533420214 2.273132637048167 C 10.538558630433283 1.5630285192439657 11.231430756296502 1.1000001064500415 12 1.1 C 13.048950624407942 1.09999985471597 13.899447920724006 1.9500495208760782 13.9 2.9990000000000006 z M 13.544 6 L 10.456 6 C 9.604684814488484 5.999811949956359 8.862518492883558 6.579113995431316 8.655999999999999 7.405000000000001 L 6.993999999999999 14.057 C 6.949087749408432 14.259377888455008 7.00082563788415 14.471133674859198 7.133999999999999 14.63 C 7.29552492159201 14.833465444933692 7.539274387351227 14.954423826438266 7.798999999999999 14.96 C 8.086057992331412 14.955557715508808 8.34287529667128 14.780544391724366 8.451999999999998 14.515 L 10 9.1 L 10 13 L 9.078 22.219 C 9.057924474646427 22.41874832997887 9.123349536101328 22.61765922173752 9.258078407025312 22.76648984152766 C 9.392807277949297 22.915320461317805 9.584245430761463 23.000158042462385 9.785 23 L 9.859 23 C 10.19101964547464 22.999898168622497 10.475889150458729 22.763347237492642 10.537 22.437 L 12 14.583 L 13.463000000000001 22.437 C 13.524110849541275 22.763347237492642 13.808980354525362 22.999898168622497 14.141000000000002 23 L 14.215000000000002 23 C 14.415754569238539 23.000158042462385 14.607192722050703 22.915320461317805 14.74192159297469 22.76648984152766 C 14.876650463898674 22.61765922173752 14.942075525353575 22.41874832997887 14.922000000000002 22.219 L 14 13 L 14 9.1 L 15.548 14.515 C 15.65743368223532 14.780152409969652 15.914184251847452 14.954727069859064 16.201 14.959000000000001 C 16.460559067140714 14.953667969304108 16.704279363027823 14.83309055975996 16.866 14.63 C 16.99917436211585 14.471133674859198 17.05091225059157 14.259377888455008 17.006 14.057 L 15.344000000000001 7.405 C 15.137481507116442 6.579113995431316 14.395315185511514 5.999811949956358 13.544 6 z" stroke-linecap="round" />
</g>
<g transform="matrix(33.33 0 0 33.33 -0.04 -0.04)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: none; fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-12, -12)" d="M 0 0 L 24 0 L 24 24 L 0 24 z" stroke-linecap="round" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
<desc>Created with Fabric.js 5.2.4</desc>
<defs>
</defs>
<g transform="matrix(1 0 0 1 540 540)" id="92f8c780-682d-410e-9305-55f6c76b821a" >
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
</g>
<g transform="matrix(1 0 0 1 540 540)" id="2902fc72-5f87-4d9a-a213-49b43b827461" >
</g>
<g transform="matrix(1 0 0 1 174.64 508.98)" >
<g style="" vector-effect="non-scaling-stroke" >
<g transform="matrix(33.33 0 0 33.33 -0.01 1.63)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-12, -12.05)" d="M 13.9 2.999 C 13.900404510128258 3.767569137253463 13.437740927005041 4.4606849303964715 12.727791698439338 4.755083937232331 C 12.017842469873635 5.04948294406819 11.200454630665819 4.88717393579122 10.656851071891348 4.343856484152948 C 10.113247513116876 3.800539032514675 9.950508209994716 2.9832367548523684 10.244533420214 2.273132637048167 C 10.538558630433283 1.5630285192439657 11.231430756296502 1.1000001064500415 12 1.1 C 13.048950624407942 1.09999985471597 13.899447920724006 1.9500495208760782 13.9 2.9990000000000006 z M 13.544 6 L 10.456 6 C 9.604684814488484 5.999811949956359 8.862518492883558 6.579113995431316 8.655999999999999 7.405000000000001 L 6.993999999999999 14.057 C 6.949087749408432 14.259377888455008 7.00082563788415 14.471133674859198 7.133999999999999 14.63 C 7.29552492159201 14.833465444933692 7.539274387351227 14.954423826438266 7.798999999999999 14.96 C 8.086057992331412 14.955557715508808 8.34287529667128 14.780544391724366 8.451999999999998 14.515 L 10 9.1 L 10 13 L 9.078 22.219 C 9.057924474646427 22.41874832997887 9.123349536101328 22.61765922173752 9.258078407025312 22.76648984152766 C 9.392807277949297 22.915320461317805 9.584245430761463 23.000158042462385 9.785 23 L 9.859 23 C 10.19101964547464 22.999898168622497 10.475889150458729 22.763347237492642 10.537 22.437 L 12 14.583 L 13.463000000000001 22.437 C 13.524110849541275 22.763347237492642 13.808980354525362 22.999898168622497 14.141000000000002 23 L 14.215000000000002 23 C 14.415754569238539 23.000158042462385 14.607192722050703 22.915320461317805 14.74192159297469 22.76648984152766 C 14.876650463898674 22.61765922173752 14.942075525353575 22.41874832997887 14.922000000000002 22.219 L 14 13 L 14 9.1 L 15.548 14.515 C 15.65743368223532 14.780152409969652 15.914184251847452 14.954727069859064 16.201 14.959000000000001 C 16.460559067140714 14.953667969304108 16.704279363027823 14.83309055975996 16.866 14.63 C 16.99917436211585 14.471133674859198 17.05091225059157 14.259377888455008 17.006 14.057 L 15.344000000000001 7.405 C 15.137481507116442 6.579113995431316 14.395315185511514 5.999811949956358 13.544 6 z" stroke-linecap="round" />
</g>
<g transform="matrix(33.33 0 0 33.33 -0.04 -0.04)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: none; fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-12, -12)" d="M 0 0 L 24 0 L 24 24 L 0 24 z" stroke-linecap="round" />
</g>
</g>
</g>
<g transform="matrix(1 0 0 1 508.64 510.94)" >
<g style="" vector-effect="non-scaling-stroke" >
<g transform="matrix(33.33 0 0 33.33 -0.01 1.63)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-12, -12.05)" d="M 13.9 2.999 C 13.900404510128258 3.767569137253463 13.437740927005041 4.4606849303964715 12.727791698439338 4.755083937232331 C 12.017842469873635 5.04948294406819 11.200454630665819 4.88717393579122 10.656851071891348 4.343856484152948 C 10.113247513116876 3.800539032514675 9.950508209994716 2.9832367548523684 10.244533420214 2.273132637048167 C 10.538558630433283 1.5630285192439657 11.231430756296502 1.1000001064500415 12 1.1 C 13.048950624407942 1.09999985471597 13.899447920724006 1.9500495208760782 13.9 2.9990000000000006 z M 13.544 6 L 10.456 6 C 9.604684814488484 5.999811949956359 8.862518492883558 6.579113995431316 8.655999999999999 7.405000000000001 L 6.993999999999999 14.057 C 6.949087749408432 14.259377888455008 7.00082563788415 14.471133674859198 7.133999999999999 14.63 C 7.29552492159201 14.833465444933692 7.539274387351227 14.954423826438266 7.798999999999999 14.96 C 8.086057992331412 14.955557715508808 8.34287529667128 14.780544391724366 8.451999999999998 14.515 L 10 9.1 L 10 13 L 9.078 22.219 C 9.057924474646427 22.41874832997887 9.123349536101328 22.61765922173752 9.258078407025312 22.76648984152766 C 9.392807277949297 22.915320461317805 9.584245430761463 23.000158042462385 9.785 23 L 9.859 23 C 10.19101964547464 22.999898168622497 10.475889150458729 22.763347237492642 10.537 22.437 L 12 14.583 L 13.463000000000001 22.437 C 13.524110849541275 22.763347237492642 13.808980354525362 22.999898168622497 14.141000000000002 23 L 14.215000000000002 23 C 14.415754569238539 23.000158042462385 14.607192722050703 22.915320461317805 14.74192159297469 22.76648984152766 C 14.876650463898674 22.61765922173752 14.942075525353575 22.41874832997887 14.922000000000002 22.219 L 14 13 L 14 9.1 L 15.548 14.515 C 15.65743368223532 14.780152409969652 15.914184251847452 14.954727069859064 16.201 14.959000000000001 C 16.460559067140714 14.953667969304108 16.704279363027823 14.83309055975996 16.866 14.63 C 16.99917436211585 14.471133674859198 17.05091225059157 14.259377888455008 17.006 14.057 L 15.344000000000001 7.405 C 15.137481507116442 6.579113995431316 14.395315185511514 5.999811949956358 13.544 6 z" stroke-linecap="round" />
</g>
<g transform="matrix(33.33 0 0 33.33 -0.04 -0.04)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: none; fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-12, -12)" d="M 0 0 L 24 0 L 24 24 L 0 24 z" stroke-linecap="round" />
</g>
</g>
</g>
<g transform="matrix(1 0 0 1 844.94 511.75)" >
<g style="" vector-effect="non-scaling-stroke" >
<g transform="matrix(33.33 0 0 33.33 -0.01 1.63)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-12, -12.05)" d="M 13.9 2.999 C 13.900404510128258 3.767569137253463 13.437740927005041 4.4606849303964715 12.727791698439338 4.755083937232331 C 12.017842469873635 5.04948294406819 11.200454630665819 4.88717393579122 10.656851071891348 4.343856484152948 C 10.113247513116876 3.800539032514675 9.950508209994716 2.9832367548523684 10.244533420214 2.273132637048167 C 10.538558630433283 1.5630285192439657 11.231430756296502 1.1000001064500415 12 1.1 C 13.048950624407942 1.09999985471597 13.899447920724006 1.9500495208760782 13.9 2.9990000000000006 z M 13.544 6 L 10.456 6 C 9.604684814488484 5.999811949956359 8.862518492883558 6.579113995431316 8.655999999999999 7.405000000000001 L 6.993999999999999 14.057 C 6.949087749408432 14.259377888455008 7.00082563788415 14.471133674859198 7.133999999999999 14.63 C 7.29552492159201 14.833465444933692 7.539274387351227 14.954423826438266 7.798999999999999 14.96 C 8.086057992331412 14.955557715508808 8.34287529667128 14.780544391724366 8.451999999999998 14.515 L 10 9.1 L 10 13 L 9.078 22.219 C 9.057924474646427 22.41874832997887 9.123349536101328 22.61765922173752 9.258078407025312 22.76648984152766 C 9.392807277949297 22.915320461317805 9.584245430761463 23.000158042462385 9.785 23 L 9.859 23 C 10.19101964547464 22.999898168622497 10.475889150458729 22.763347237492642 10.537 22.437 L 12 14.583 L 13.463000000000001 22.437 C 13.524110849541275 22.763347237492642 13.808980354525362 22.999898168622497 14.141000000000002 23 L 14.215000000000002 23 C 14.415754569238539 23.000158042462385 14.607192722050703 22.915320461317805 14.74192159297469 22.76648984152766 C 14.876650463898674 22.61765922173752 14.942075525353575 22.41874832997887 14.922000000000002 22.219 L 14 13 L 14 9.1 L 15.548 14.515 C 15.65743368223532 14.780152409969652 15.914184251847452 14.954727069859064 16.201 14.959000000000001 C 16.460559067140714 14.953667969304108 16.704279363027823 14.83309055975996 16.866 14.63 C 16.99917436211585 14.471133674859198 17.05091225059157 14.259377888455008 17.006 14.057 L 15.344000000000001 7.405 C 15.137481507116442 6.579113995431316 14.395315185511514 5.999811949956358 13.544 6 z" stroke-linecap="round" />
</g>
<g transform="matrix(33.33 0 0 33.33 -0.04 -0.04)" >
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: none; fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-12, -12)" d="M 0 0 L 24 0 L 24 24 L 0 24 z" stroke-linecap="round" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -0,0 +1,6 @@
// _base.scss
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}

View File

View File

@ -0,0 +1,5 @@
.card{
// background-color: red;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
border-radius: 5px;
}

View File

@ -0,0 +1,38 @@
/* Styles for custom zoom control buttons */
.custom-zoom-control {
position: absolute;
top: 10px;
right: 10px;
z-index: 1000;
}
.custom-zoom-control button {
background-color: #fff;
border: 2px solid #bbb;
border-radius: 2px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
color: #333;
cursor: pointer;
display: block;
font-size: 18px;
line-height: 18px;
margin-bottom: 5px;
outline: none;
padding: 5px;
text-align: center;
text-decoration: none;
transition: background-color 0.2s ease;
width: 30px;
}
.custom-zoom-control button:hover {
background-color: #f4f4f4;
}
.custom-zoom-control button:active {
background-color: #e6e6e6;
}
.custom-zoom-control button:first-child {
margin-bottom: 0;
}

Some files were not shown because too many files have changed in this diff Show More