mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
initial commit
This commit is contained in:
commit
37987025f9
30
README.md
Normal file
30
README.md
Normal file
@ -0,0 +1,30 @@
|
||||
# Utopia UI
|
||||
Reuseable React Components to build mapping apps for all kinds of communities
|
||||
|
||||
|
||||
## Getting Started
|
||||
|
||||
install via npm
|
||||
```
|
||||
npm install utopia-ui
|
||||
```
|
||||
|
||||
import in your React App
|
||||
|
||||
```
|
||||
import Map from 'utopia-ui'
|
||||
```
|
||||
|
||||
use the Map UI Component
|
||||
|
||||
```
|
||||
<Map height='100vh' width='100hw'></Map>
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
|
||||
Option | Type | Default | Description
|
||||
--- | --- | --- | ---
|
||||
height | x | |
|
||||
width | x | |
|
||||
2406
package-lock.json
generated
Normal file
2406
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
40
package.json
Normal file
40
package.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "utopia-ui",
|
||||
"version": "1.0.0",
|
||||
"description": "Reuseable React Components to build mapping apps for all kinds of communities ",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"start": "rollup -c -w"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"keywords": [],
|
||||
"author": "Anton Tranelis",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/leaflet": "^1.7.11",
|
||||
"@types/react": "^18.0.14",
|
||||
"@types/react-dom": "^18.0.5",
|
||||
"@types/react-leaflet": "^2.8.2",
|
||||
"@types/react-leaflet-markercluster": "^3.0.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"rollup": "^2.75.7",
|
||||
"rollup-plugin-sass": "^1.2.12",
|
||||
"rollup-plugin-typescript2": "^0.32.1",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"leaflet": "^1.8.0",
|
||||
"react-leaflet": "^4.0.0",
|
||||
"react-leaflet-markercluster": "^3.0.0-rc1"
|
||||
}
|
||||
}
|
||||
22
rollup.config.js
Normal file
22
rollup.config.js
Normal file
@ -0,0 +1,22 @@
|
||||
import sass from 'rollup-plugin-sass'
|
||||
import typescript from 'rollup-plugin-typescript2'
|
||||
|
||||
import pkg from './package.json'
|
||||
|
||||
export default {
|
||||
input: 'src/index.tsx',
|
||||
output: [
|
||||
{
|
||||
file: pkg.main,
|
||||
format: 'cjs',
|
||||
exports: 'named',
|
||||
sourcemap: true,
|
||||
strict: false
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
sass({ insert: true }),
|
||||
typescript()
|
||||
],
|
||||
external: ['react', 'react-dom']
|
||||
}
|
||||
50
src/Components/Map/MarkerPopup.tsx
Normal file
50
src/Components/Map/MarkerPopup.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import * as React from 'react'
|
||||
import { Popup } from 'react-leaflet'
|
||||
|
||||
export interface IMarkerPopupProps {
|
||||
item: IMapItem;
|
||||
}
|
||||
|
||||
export interface IMapItem {
|
||||
id?: string,
|
||||
date_created?: string,
|
||||
date_updated?: string | null,
|
||||
name: string,
|
||||
text: string,
|
||||
position: IGeometry,
|
||||
start?: string,
|
||||
end?: string,
|
||||
tags: ITag[],
|
||||
[key: string]:any
|
||||
}
|
||||
|
||||
export interface IGeometry {
|
||||
type: string;
|
||||
coordinates: number[];
|
||||
}
|
||||
|
||||
export interface ITag {
|
||||
Tags_id :
|
||||
{
|
||||
color: string;
|
||||
id: string;
|
||||
}
|
||||
}
|
||||
|
||||
const MarkerPopup = (props:IMarkerPopupProps) => {
|
||||
const item:IMapItem = props.item;
|
||||
return (
|
||||
<Popup>
|
||||
<b style={{ fontSize: '1.0rem' }}>{item.name}</b>
|
||||
|
||||
<p>{item.start || ""} {item.end || ""}</p>
|
||||
|
||||
<p>{item.text}</p>
|
||||
{item.tags.map((tag:ITag) => (
|
||||
<span key={tag.Tags_id.id}>#{tag.Tags_id.id} </span>
|
||||
))}
|
||||
</Popup>
|
||||
)
|
||||
}
|
||||
|
||||
export default MarkerPopup;
|
||||
38
src/Utils/MarkerIconFactory.ts
Normal file
38
src/Utils/MarkerIconFactory.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import * as L from 'leaflet';
|
||||
|
||||
const createSvg = (shape:string, markerColor:string, borderColor:string) => {
|
||||
var svgMap = {
|
||||
circle: '<svg width="32" height="44" viewBox="0 0 35 45" xmlns="http://www.w3.org/2000/svg"><path d="M17.5 2.746c-8.284 0-15 6.853-15 15.307 0 .963.098 1.902.265 2.816a15.413 15.413 0 002.262 5.684l.134.193 12.295 17.785 12.439-17.863.056-.08a15.422 15.422 0 002.343-6.112c.123-.791.206-1.597.206-2.423 0-8.454-6.716-15.307-15-15.307" fill="' + markerColor + '" /><path d="M17.488 2.748c-8.284 0-15 6.853-15 15.307 0 .963.098 1.902.265 2.816a15.413 15.413 0 002.262 5.684l.134.193 12.295 17.785 12.44-17.863.055-.08a15.422 15.422 0 002.343-6.112c.124-.791.206-1.597.206-2.423 0-8.454-6.716-15.307-15-15.307m0 1.071c7.68 0 13.929 6.386 13.929 14.236 0 .685-.064 1.423-.193 2.258-.325 2.075-1.059 3.99-2.164 5.667l-.055.078-11.557 16.595L6.032 26.14l-.12-.174a14.256 14.256 0 01-2.105-5.29 14.698 14.698 0 01-.247-2.62c0-7.851 6.249-14.237 13.928-14.237" fill="' + borderColor + '" opacity="1" /></svg>',
|
||||
square: '<svg width="33" height="44" viewBox="0 0 35 45" xmlns="http://www.w3.org/2000/svg"><path d="M28.205 3.217H6.777c-2.367 0-4.286 1.87-4.286 4.179v19.847c0 2.308 1.919 4.179 4.286 4.179h5.357l5.337 13.58 5.377-13.58h5.357c2.366 0 4.285-1.87 4.285-4.179V7.396c0-2.308-1.919-4.179-4.285-4.179" fill="' + markerColor + '" /><g opacity="1" transform="matrix(1.0714 0 0 -1.0714 -233.22 146.783)"><path d="M244 134h-20c-2.209 0-4-1.746-4-3.9v-18.525c0-2.154 1.791-3.9 4-3.9h5L233.982 95 239 107.675h5c2.209 0 4 1.746 4 3.9V130.1c0 2.154-1.791 3.9-4 3.9m0-1c1.654 0 3-1.301 3-2.9v-18.525c0-1.599-1.346-2.9-3-2.9h-5.68l-.25-.632-4.084-10.318-4.055 10.316-.249.634H224c-1.654 0-3 1.301-3 2.9V130.1c0 1.599 1.346 2.9 3 2.9h20" fill="'+ borderColor +'" /></g></svg>',
|
||||
star: '<svg width="34" height="44" viewBox="0 0 35 45" xmlns="http://www.w3.org/2000/svg"><path d="M32.92 16.93l-3.525-3.525V8.419a1.983 1.983 0 00-1.983-1.982h-4.985L18.9 2.91a1.984 1.984 0 00-2.803 0l-3.524 3.526H7.588a1.983 1.983 0 00-1.982 1.982v4.986L2.081 16.93a1.982 1.982 0 000 2.803l3.525 3.526v4.984c0 1.096.888 1.983 1.982 1.983h4.986L17.457 45l4.97-14.773h4.985a1.983 1.983 0 001.983-1.983V23.26l3.525-3.526a1.982 1.982 0 000-2.803" fill="' + markerColor + '" /><g opacity=".15" transform="matrix(1.0667 0 0 -1.0667 -347.3 97.26)"><path d="M342 89c-.476 0-.951-.181-1.314-.544l-3.305-3.305h-4.673a1.858 1.858 0 01-1.859-1.858v-4.674l-3.305-3.305a1.857 1.857 0 010-2.627l3.305-3.305v-4.674a1.86 1.86 0 011.859-1.859h4.673L341.959 49l4.659 13.849h4.674a1.86 1.86 0 011.859 1.859v4.674l3.305 3.305a1.858 1.858 0 010 2.627l-3.305 3.305v4.674a1.859 1.859 0 01-1.859 1.858h-4.674l-3.304 3.305A1.851 1.851 0 01342 89m0-1a.853.853 0 00.607-.251l3.304-3.305.293-.293h5.088a.86.86 0 00.859-.858v-5.088l3.598-3.598A.852.852 0 00356 74a.85.85 0 00-.251-.606l-3.598-3.598v-5.088a.86.86 0 00-.859-.859h-5.393l-.229-.681-3.702-11.006-3.637 11.001-.227.686h-5.396a.86.86 0 00-.859.859v5.088l-3.598 3.598c-.162.162-.251.377-.251.606s.089.445.251.607l3.598 3.598v5.088a.86.86 0 00.859.858h5.087l3.598 3.598A.853.853 0 00342 88" fill="#231f20" /></g></svg>',
|
||||
penta: '<svg width="33" height="44" viewBox="0 0 35 45" xmlns="http://www.w3.org/2000/svg"><path d="M1.872 17.35L9.679 2.993h15.615L33.1 17.35 17.486 44.992z" fill="' + markerColor + '" /><g opacity=".15" transform="matrix(1.0769 0 0 -1.0769 -272.731 48.23)"><path d="M276.75 42h-14.5L255 28.668 269.5 3 284 28.668zm-.595-1l6.701-12.323L269.5 5.033l-13.356 23.644L262.845 41z" fill="#231f20" /></g></svg>'
|
||||
};
|
||||
return svgMap[shape];
|
||||
}
|
||||
|
||||
const addIcon = (icon:string) => {
|
||||
switch(icon) {
|
||||
case "circle-solid":
|
||||
return '<svg fill="#fff" style="position: relative; top: -38px;left: -1px;" width="13"xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M512 256C512 397.4 397.4 512 256 512C114.6 512 0 397.4 0 256C0 114.6 114.6 0 256 0C397.4 0 512 114.6 512 256z"/></svg>';
|
||||
break;
|
||||
case "calendar-days-solid":
|
||||
return '<svg fill="#fff" style="position: relative; top: -40px;left: 0px;" width="13" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M160 32V64H288V32C288 14.33 302.3 0 320 0C337.7 0 352 14.33 352 32V64H400C426.5 64 448 85.49 448 112V160H0V112C0 85.49 21.49 64 48 64H96V32C96 14.33 110.3 0 128 0C145.7 0 160 14.33 160 32zM0 192H448V464C448 490.5 426.5 512 400 512H48C21.49 512 0 490.5 0 464V192zM64 304C64 312.8 71.16 320 80 320H112C120.8 320 128 312.8 128 304V272C128 263.2 120.8 256 112 256H80C71.16 256 64 263.2 64 272V304zM192 304C192 312.8 199.2 320 208 320H240C248.8 320 256 312.8 256 304V272C256 263.2 248.8 256 240 256H208C199.2 256 192 263.2 192 272V304zM336 256C327.2 256 320 263.2 320 272V304C320 312.8 327.2 320 336 320H368C376.8 320 384 312.8 384 304V272C384 263.2 376.8 256 368 256H336zM64 432C64 440.8 71.16 448 80 448H112C120.8 448 128 440.8 128 432V400C128 391.2 120.8 384 112 384H80C71.16 384 64 391.2 64 400V432zM208 384C199.2 384 192 391.2 192 400V432C192 440.8 199.2 448 208 448H240C248.8 448 256 440.8 256 432V400C256 391.2 248.8 384 240 384H208zM320 432C320 440.8 327.2 448 336 448H368C376.8 448 384 440.8 384 432V400C384 391.2 376.8 384 368 384H336C327.2 384 320 391.2 320 400V432z"/></svg>';
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
const MarkerIconFactory = (shape:string, color1:string, color2:string, icon:string) =>
|
||||
{
|
||||
return L.divIcon({
|
||||
html: `${createSvg(shape, color1, color2)}${addIcon(icon)}`,
|
||||
iconAnchor: [17,40],
|
||||
popupAnchor: [0,-40],
|
||||
iconSize: new L.Point(40, 46),
|
||||
className: "leaflet-data-marker",
|
||||
shadowAnchor: [0, 0]
|
||||
});
|
||||
}
|
||||
|
||||
export default MarkerIconFactory ;
|
||||
49
src/index.tsx
Normal file
49
src/index.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
import { TileLayer, MapContainer, Marker, LayersControl } from "react-leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import * as React from "react";
|
||||
import MarkerIconFactory from './Utils/MarkerIconFactory';
|
||||
import MarkerPopup, { IMapItem } from "./Components/Map/MarkerPopup";
|
||||
import { places, events } from './sampleData/data'
|
||||
import "./styles.scss"
|
||||
|
||||
export interface IMapProps {
|
||||
height: string,
|
||||
width: string,
|
||||
places?: IMapItem[],
|
||||
events?: IMapItem[]
|
||||
}
|
||||
|
||||
const Map = (props: IMapProps) => {
|
||||
|
||||
return (
|
||||
<MapContainer style={{ height: props.height, width: props.width }} center={[51.3, 9.6]} zoom={8} >
|
||||
<LayersControl position="topright">
|
||||
<TileLayer
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
/>
|
||||
<LayersControl.Overlay checked name="Places">
|
||||
{places &&
|
||||
(places).map((place) => (
|
||||
<Marker icon={MarkerIconFactory('circle', '#f18e1c', 'RGBA(35, 31, 32, 0.2)', 'circle-solid')} key={place.id} position={[place.position.coordinates[1], place.position.coordinates[0]]}>
|
||||
<MarkerPopup item={place} />
|
||||
</Marker>
|
||||
))
|
||||
}
|
||||
</LayersControl.Overlay>
|
||||
<LayersControl.Overlay checked name="Events">
|
||||
{events &&
|
||||
(events).map((event) => (
|
||||
<Marker icon={MarkerIconFactory('square', '#6d398b', 'RGBA(35, 31, 32, 0.2)', 'calendar-days-solid')} key={event.id} position={[event.position.coordinates[1], event.position.coordinates[0]]}>
|
||||
<MarkerPopup item={event} />
|
||||
</Marker>
|
||||
))
|
||||
}
|
||||
</LayersControl.Overlay>
|
||||
</LayersControl>
|
||||
</MapContainer>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
export default Map;
|
||||
94
src/sampleData/data.ts
Normal file
94
src/sampleData/data.ts
Normal file
@ -0,0 +1,94 @@
|
||||
import { IMapItem } from "../Components/Map/MarkerPopup";
|
||||
|
||||
export const events:IMapItem[] = [
|
||||
{
|
||||
"id": "1af74f62-9fcc-43c2-b63b-cc320dd4fcda",
|
||||
"date_created": "2022-05-09T21:35:09.250Z",
|
||||
"date_updated": null,
|
||||
"name": "bla bla",
|
||||
"text": "fsddfsf",
|
||||
"position": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
10.1233030812617,
|
||||
50.7884682638985
|
||||
]
|
||||
},
|
||||
"start": "2022-05-17T12:00:00",
|
||||
"end": "2022-05-25T12:00:00",
|
||||
"tags": [
|
||||
{
|
||||
"Tags_id": {
|
||||
"color": "#75507B",
|
||||
"id": "Docutopia"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Tags_id": {
|
||||
"color": "#3465A4",
|
||||
"id": "Coding"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "65bbc003-b6de-4904-b85c-8ab6c92fe0db",
|
||||
"date_created": "2022-03-14T10:20:11.534Z",
|
||||
"date_updated": "2022-04-05T08:58:38.790Z",
|
||||
"name": "Hackathon",
|
||||
"text": "still in progress",
|
||||
"position": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
9.97875748947354,
|
||||
51.1204618942726
|
||||
]
|
||||
},
|
||||
"start": "2022-03-25T12:00:00",
|
||||
"end": "2022-05-12T12:00:00",
|
||||
"tags": [
|
||||
{
|
||||
"Tags_id": {
|
||||
"color": "#75507B",
|
||||
"id": "Docutopia"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Tags_id": {
|
||||
"color": "#3465A4",
|
||||
"id": "Coding"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export const places = [{
|
||||
"id": "938529f4-fa0b-4c98-9381-bda13b0c2ac7",
|
||||
"date_created": "2022-04-05T08:20:45.178Z",
|
||||
"date_updated": "2022-04-05T08:57:41.311Z",
|
||||
"name": "Rainbow Crystal Garten",
|
||||
"text": "welcome home",
|
||||
"position": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
9.50282340471136,
|
||||
51.3348944083875
|
||||
]
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"Tags_id": {
|
||||
"color": "#75507B",
|
||||
"id": "Docutopia"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Tags_id": {
|
||||
"color": "#4E9A06",
|
||||
"id": "Rainbow"
|
||||
}
|
||||
}
|
||||
]
|
||||
}];
|
||||
|
||||
5
src/styles.scss
Normal file
5
src/styles.scss
Normal file
@ -0,0 +1,5 @@
|
||||
.leaflet-data-marker {
|
||||
|
||||
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAQCAYAAACcN8ZaAAAB3klEQVR42s3U4UdDURzG8czMXJnJ1Vwzc6VJZjaZJdlMlpQsKdmUFNOUspRSSqUolfQfr+fF98Vx5mwv9qbDx7LdznnO7/7Omej3+/+Ga0QMUYkhbvBgmhzCQxwxibIGrGEF8CQhU+LLtKQkQNqScUgjxRxTBIxbgfgD/BgnhM8kM5KTeclLQYqGkkMRBckzR8ic/mAgd5BAZplsUaqyIg2sDtHg2brUZJk5SmwopErJUWE8SpmTMhNvya60Zd/SNrR4bkeaskG4uiwRZk6yrJEYFibGAxn+scECHTmTnuVCzvmty3PHciB7bGKN6lQkzysPqIrHmpFhYbKUtckC1/Ioz4ZHuZdbuSLYiRxRpSZVWXZVxAzC0R4Ik5SQsu6w8yd5l2/5kg95I9SdXMoZQfYIUjeqEUrgOkXGPeN4TYRhxy8E+ZUf+eS7B7miIoeybVSjKDnm8u3+gH3pDTYwu1igATvs/pXqvBKiR4i2bNJfi1ZfUAnjgrOG8wY2quNzBKuU/ZS+uSFEl5O0xRGuUIlZCcw7xG5QPkeHYUSNV5WXGou2sC3rBC0LjenqCXGO0WEiTJa0Lr4KixdHBrDGuGGiRqCUpFk8pGIpQtCU7p4YPwxYxEMCk1aAMQZh8Ac8PfbIzYPJOwAAAABJRU5ErkJggg==') no-repeat;
|
||||
background-position: 6px 32px;
|
||||
}
|
||||
29
tsconfig.json
Normal file
29
tsconfig.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"module": "esnext",
|
||||
"target": "es5",
|
||||
"lib": ["es6", "dom", "es2016", "es2017"],
|
||||
"sourceMap": true,
|
||||
"allowJs": false,
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"declarationDir": "./types",
|
||||
"moduleResolution": "node",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist", "example", "rollup.config.js"],
|
||||
"typeRoots": [
|
||||
"./types",
|
||||
"./node_modules/@types/"
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user