From 4041e9472ac443015d8efc87721466a9da8ec144 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Mon, 3 Mar 2025 19:42:59 +0100 Subject: [PATCH 01/13] refactor(source): css (#171) * separate css into several files by topic, move all css into assets Make separate files for all css topics like leaflet and move its into the assets folder. This way only one include from index.ts points to an index.tsx in assets including all the css files. * fix up compiling * extract more css imports, unify imports in a css.tsx file * separate external css & internal css * renamed icons.css in marker-icons.css --------- Co-authored-by: Anton Tranelis --- .../Subcomponents/Controls/LocateControl.tsx | 1 - src/Components/Map/UtopiaMap.css | 188 ------------------ src/Components/Map/UtopiaMap.tsx | 1 - src/Components/Map/UtopiaMapInner.tsx | 2 - .../Profile/Subcomponents/AvatarWidget.tsx | 1 - .../Profile/Subcomponents/ColorPicker.tsx | 1 - .../Profile/Subcomponents/GalleryView.tsx | 2 - .../css/color-picker.css} | 14 +- src/assets/css/custom-file-upload.css | 18 ++ src/assets/css/leaflet.css | 51 +++++ src/assets/css/marker-icons.css | 118 +++++++++++ src/assets/css/masonry.css | 27 +++ src/assets/css/misc.css | 23 +++ src/assets/css/tailwind.css | 24 +++ src/assets/css/toastify.css | 26 +++ src/css.tsx | 15 ++ src/index.css | 105 ---------- src/index.tsx | 3 +- 18 files changed, 311 insertions(+), 309 deletions(-) delete mode 100644 src/Components/Map/UtopiaMap.css rename src/{Components/Profile/Subcomponents/ColorPicker.css => assets/css/color-picker.css} (89%) create mode 100644 src/assets/css/custom-file-upload.css create mode 100644 src/assets/css/leaflet.css create mode 100644 src/assets/css/marker-icons.css create mode 100644 src/assets/css/masonry.css create mode 100644 src/assets/css/misc.css create mode 100644 src/assets/css/tailwind.css create mode 100644 src/assets/css/toastify.css create mode 100644 src/css.tsx delete mode 100644 src/index.css diff --git a/src/Components/Map/Subcomponents/Controls/LocateControl.tsx b/src/Components/Map/Subcomponents/Controls/LocateControl.tsx index 3380f6bc..db555bf2 100644 --- a/src/Components/Map/Subcomponents/Controls/LocateControl.tsx +++ b/src/Components/Map/Subcomponents/Controls/LocateControl.tsx @@ -12,7 +12,6 @@ import TargetSVG from '#assets/target.svg' // eslint-disable-next-line import/no-unassigned-import import 'leaflet.locatecontrol' -import 'leaflet.locatecontrol/dist/L.Control.Locate.css' // Converts leaflet.locatecontrol to a React Component export const LocateControl = () => { diff --git a/src/Components/Map/UtopiaMap.css b/src/Components/Map/UtopiaMap.css deleted file mode 100644 index a1f1a014..00000000 --- a/src/Components/Map/UtopiaMap.css +++ /dev/null @@ -1,188 +0,0 @@ -.leaflet-container { - text-align: left; - background-image: url("data:image/svg+xml,%3Csvg width='40' height='40' stroke='%23000' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cstyle%3E.spinner_V8m1%7Btransform-origin:center;animation:spinner_zKoa 2s linear infinite%7D.spinner_V8m1 circle%7Bstroke-linecap:round;animation:spinner_YpZS 1.5s ease-out infinite%7D%40keyframes spinner_zKoa%7B100%25%7Btransform:rotate(360deg)%7D%7D%40keyframes spinner_YpZS%7B0%25%7Bstroke-dasharray:0 150;stroke-dashoffset:0%7D47.5%25%7Bstroke-dasharray:42 150;stroke-dashoffset:-16%7D95%25%2C100%25%7Bstroke-dasharray:42 150;stroke-dashoffset:-59%7D%7D%3C%2Fstyle%3E%3Cg class='spinner_V8m1'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3'%3E%3C%2Fcircle%3E%3C%2Fg%3E%3C%2Fsvg%3E"); - background-repeat: no-repeat; - background-attachment: fixed; - background-position: 50% 80%; - } - - input { - box-sizing: border-box; - } - - textarea { - box-sizing: border-box; - } - - .leaflet-control-attribution { - display: none; - } - - .leaflet-control-locate { - display: none; - } - - .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; - } - - .crosshair-cursor-enabled { - cursor: crosshair; - } - - .leaflet-container { - cursor: inherit; - } - - .calendar-icon { - position: relative; - top: -35px; - left: 10px; - width: 13px; - } - - .user-icon { - position: relative; - top: -36px; - left: 10px; - width: 13px; - } - - .circle-icon { - position: relative; - top: -33px; - left: 10px; - width: 13px; - } - - .fire-icon { - position: relative; - top: -36px; - left: 10px; - width: 13px; - } - - .tree-icon { - position: relative; - top: -38px; - left: 4px; - width: 24px; - } - - .music-icon { - position: relative; - top: -35px; - left: 4px; - width: 24px; - } - - .quest-icon { - position: relative; - top: -34px; - left: 4px; - width: 24px; - } - - .drum-icon { - position: relative; - top: -38px; - left: 4px; - width: 24px; - } - - - .compass-icon { - position: relative; - top: -36.5px; - left: 4px; - width: 24px; - } - - .group-icon { - position: relative; - top: -37px; - left: 4px; - width: 24px; - } - - .liebevoll-jetzt-icon{ - position: relative; - top: -35px; - left: 4px; - width: 24px; - } - - .staff-snake-icon { - position: relative; - top: -35px; - left: 4px; - width: 24px; - } - - .flower-icon { - position: relative; - top: -35px; - left: 4px; - width: 24px; - } - - .network-icon { - position: relative; - top: -35px; - left: 4px; - width: 24px; - } - - .shop-icon { - position: relative; - top: -34px; - left: 4px; - width: 24px; - } - - .plant-icon { - position: relative; - top: -34px; - left: 4px; - width: 24px; - } - - .circle-dot-icon { - position: relative; - top: -36px; - left: 4px; - width: 24px; - } - - .leaflet-popup-scrolled { - overflow-x: hidden; - } - - .leaflet-popup-content-wrapper, .leaflet-popup-tip{ - background-color: theme('colors.base-100'); - color: theme('colors.base-content'); - - } - - .leaflet-tooltip { - background-color: theme('colors.base-100'); - color: theme('colors.base-content'); - border-width: 0px; - } - - .leaflet-tooltip { - border-radius: 1em; - transition: opacity 500ms; - transition-delay: 50ms; - - } - - .leaflet-tooltip-top::before { - border-top-color: theme('colors.base-100'); - } - - .marker-cluster span { - color: #000; - } \ No newline at end of file diff --git a/src/Components/Map/UtopiaMap.tsx b/src/Components/Map/UtopiaMap.tsx index ed612563..6d89cebb 100644 --- a/src/Components/Map/UtopiaMap.tsx +++ b/src/Components/Map/UtopiaMap.tsx @@ -6,7 +6,6 @@ import { ContextWrapper } from '#components/AppShell/ContextWrapper' import { UtopiaMapInner } from './UtopiaMapInner' import type { UtopiaMapProps } from '#types/UtopiaMapProps' -import 'react-toastify/dist/ReactToastify.css' /** * @category Map diff --git a/src/Components/Map/UtopiaMapInner.tsx b/src/Components/Map/UtopiaMapInner.tsx index 927a7865..25198f21 100644 --- a/src/Components/Map/UtopiaMapInner.tsx +++ b/src/Components/Map/UtopiaMapInner.tsx @@ -8,11 +8,9 @@ /* eslint-disable @typescript-eslint/no-unsafe-argument */ import { Children, cloneElement, isValidElement, useEffect, useRef, useState } from 'react' import { TileLayer, useMapEvents, GeoJSON, useMap } from 'react-leaflet' -import 'leaflet/dist/leaflet.css' import MarkerClusterGroup from 'react-leaflet-cluster' import { Outlet, useLocation } from 'react-router-dom' import { toast } from 'react-toastify' -import './UtopiaMap.css' import { containsUUID } from '#utils/ContainsUUID' diff --git a/src/Components/Profile/Subcomponents/AvatarWidget.tsx b/src/Components/Profile/Subcomponents/AvatarWidget.tsx index 94d1e1f4..b16f0def 100644 --- a/src/Components/Profile/Subcomponents/AvatarWidget.tsx +++ b/src/Components/Profile/Subcomponents/AvatarWidget.tsx @@ -8,7 +8,6 @@ import { ReactCrop, centerCrop, makeAspectCrop } from 'react-image-crop' import UserSVG from '#assets/user.svg' import { useAppState } from '#components/AppShell/hooks/useAppState' -import 'react-image-crop/dist/ReactCrop.css' import DialogModal from '#components/Templates/DialogModal' import type { Crop } from 'react-image-crop' diff --git a/src/Components/Profile/Subcomponents/ColorPicker.tsx b/src/Components/Profile/Subcomponents/ColorPicker.tsx index 84160fc0..b75ed28b 100644 --- a/src/Components/Profile/Subcomponents/ColorPicker.tsx +++ b/src/Components/Profile/Subcomponents/ColorPicker.tsx @@ -5,7 +5,6 @@ import { useCallback, useEffect, useRef, useState } from 'react' import { HexColorPicker } from 'react-colorful' -import './ColorPicker.css' import useClickOutside from '#components/Profile/hooks/useClickOutside' // eslint-disable-next-line react/prop-types diff --git a/src/Components/Profile/Subcomponents/GalleryView.tsx b/src/Components/Profile/Subcomponents/GalleryView.tsx index affd8515..287131ad 100644 --- a/src/Components/Profile/Subcomponents/GalleryView.tsx +++ b/src/Components/Profile/Subcomponents/GalleryView.tsx @@ -1,8 +1,6 @@ import { useState } from 'react' import { RowsPhotoAlbum } from 'react-photo-album' import ReactLightbox from 'yet-another-react-lightbox' -import 'yet-another-react-lightbox/styles.css' -import 'react-photo-album/rows.css' import { useAppState } from '#components/AppShell/hooks/useAppState' diff --git a/src/Components/Profile/Subcomponents/ColorPicker.css b/src/assets/css/color-picker.css similarity index 89% rename from src/Components/Profile/Subcomponents/ColorPicker.css rename to src/assets/css/color-picker.css index 8fb97fb2..202106fd 100644 --- a/src/Components/Profile/Subcomponents/ColorPicker.css +++ b/src/assets/css/color-picker.css @@ -1,20 +1,20 @@ .picker { position: relative; - } - - .swatch { +} + +.swatch { width: 28px; height: 28px; border-radius: 8px; border: 3px solid #fff; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), inset 0 0 0 1px rgba(0, 0, 0, 0.1); cursor: pointer; - } - - .popover { +} + +.popover { position: absolute; top: 0; left: 36px; border-radius: 9px; box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15); - } \ No newline at end of file +} \ No newline at end of file diff --git a/src/assets/css/custom-file-upload.css b/src/assets/css/custom-file-upload.css new file mode 100644 index 00000000..8594a921 --- /dev/null +++ b/src/assets/css/custom-file-upload.css @@ -0,0 +1,18 @@ +.custom-file-upload { + cursor: pointer; +} + +input[type="file"] { + display: none; +} + +.custom-file-upload:hover .button { + opacity: 0.8; +} + +.custom-file-upload .button { + transition: .5s ease; + opacity: 0; + position: absolute; + transform: translate(8px, 8px); +} \ No newline at end of file diff --git a/src/assets/css/leaflet.css b/src/assets/css/leaflet.css new file mode 100644 index 00000000..5c464e19 --- /dev/null +++ b/src/assets/css/leaflet.css @@ -0,0 +1,51 @@ +.leaflet-control-attribution { + display: none; +} + +.leaflet-control-locate { + display: none; +} + +.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; +} + +.leaflet-container { + cursor: inherit; +} + +.leaflet-popup-scrolled { + overflow-x: hidden; +} + +.leaflet-popup-content-wrapper, .leaflet-popup-tip{ + background-color: theme('colors.base-100'); + color: theme('colors.base-content'); + +} + +.leaflet-tooltip { + background-color: theme('colors.base-100'); + color: theme('colors.base-content'); + border-width: 0px; +} + +.leaflet-tooltip { + border-radius: 1em; + transition: opacity 500ms; + transition-delay: 50ms; + +} + +.leaflet-tooltip-top::before { + border-top-color: theme('colors.base-100'); +} + +.leaflet-container { + text-align: left; + background-image: url("data:image/svg+xml,%3Csvg width='40' height='40' stroke='%23000' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cstyle%3E.spinner_V8m1%7Btransform-origin:center;animation:spinner_zKoa 2s linear infinite%7D.spinner_V8m1 circle%7Bstroke-linecap:round;animation:spinner_YpZS 1.5s ease-out infinite%7D%40keyframes spinner_zKoa%7B100%25%7Btransform:rotate(360deg)%7D%7D%40keyframes spinner_YpZS%7B0%25%7Bstroke-dasharray:0 150;stroke-dashoffset:0%7D47.5%25%7Bstroke-dasharray:42 150;stroke-dashoffset:-16%7D95%25%2C100%25%7Bstroke-dasharray:42 150;stroke-dashoffset:-59%7D%7D%3C%2Fstyle%3E%3Cg class='spinner_V8m1'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3'%3E%3C%2Fcircle%3E%3C%2Fg%3E%3C%2Fsvg%3E"); + background-repeat: no-repeat; + background-attachment: fixed; + background-position: 50% 80%; +} \ No newline at end of file diff --git a/src/assets/css/marker-icons.css b/src/assets/css/marker-icons.css new file mode 100644 index 00000000..c69102d3 --- /dev/null +++ b/src/assets/css/marker-icons.css @@ -0,0 +1,118 @@ +.calendar-icon { + position: relative; + top: -35px; + left: 10px; + width: 13px; +} + +.user-icon { + position: relative; + top: -36px; + left: 10px; + width: 13px; +} + +.circle-icon { + position: relative; + top: -33px; + left: 10px; + width: 13px; +} + +.fire-icon { + position: relative; + top: -36px; + left: 10px; + width: 13px; +} + +.tree-icon { + position: relative; + top: -38px; + left: 4px; + width: 24px; +} + +.music-icon { + position: relative; + top: -35px; + left: 4px; + width: 24px; +} + +.quest-icon { + position: relative; + top: -34px; + left: 4px; + width: 24px; +} + +.drum-icon { + position: relative; + top: -38px; + left: 4px; + width: 24px; +} + +.compass-icon { + position: relative; + top: -36.5px; + left: 4px; + width: 24px; +} + +.group-icon { + position: relative; + top: -37px; + left: 4px; + width: 24px; +} + +.liebevoll-jetzt-icon{ + position: relative; + top: -35px; + left: 4px; + width: 24px; +} + +.staff-snake-icon { + position: relative; + top: -35px; + left: 4px; + width: 24px; +} + +.flower-icon { + position: relative; + top: -35px; + left: 4px; + width: 24px; +} + +.network-icon { + position: relative; + top: -35px; + left: 4px; + width: 24px; +} + +.shop-icon { + position: relative; + top: -34px; + left: 4px; + width: 24px; +} + +.plant-icon { + position: relative; + top: -34px; + left: 4px; + width: 24px; +} + +.circle-dot-icon { + position: relative; + top: -36px; + left: 4px; + width: 24px; +} \ No newline at end of file diff --git a/src/assets/css/masonry.css b/src/assets/css/masonry.css new file mode 100644 index 00000000..873e8c58 --- /dev/null +++ b/src/assets/css/masonry.css @@ -0,0 +1,27 @@ +.masonry { + column-count: 1; + column-gap: 1.5rem; +} + +.masonry-item { + break-inside: avoid; + margin-bottom: 1.5rem; +} + +@media (min-width: 640px) { + .masonry { + column-count: 2; + } +} + +@media (min-width: 1024px) { + .masonry { + column-count: 3; + } +} + +@media (min-width: 1536px) { + .masonry { + column-count: 4; + } +} \ No newline at end of file diff --git a/src/assets/css/misc.css b/src/assets/css/misc.css new file mode 100644 index 00000000..fa6234bb --- /dev/null +++ b/src/assets/css/misc.css @@ -0,0 +1,23 @@ +.fade { + mask-image: linear-gradient(180deg, transparent, #000 1%, #000 99%, transparent); +} + +.placeholder-center::placeholder { + text-align: center; +} + +input { + box-sizing: border-box; +} + +textarea { + box-sizing: border-box; +} + +.crosshair-cursor-enabled { + cursor: crosshair; +} + +.marker-cluster span { + color: #000; +} \ No newline at end of file diff --git a/src/assets/css/tailwind.css b/src/assets/css/tailwind.css new file mode 100644 index 00000000..0c34187f --- /dev/null +++ b/src/assets/css/tailwind.css @@ -0,0 +1,24 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +.tw-modal { + z-index: 1200 !important; +} + +.tw-menu li a { + border-radius: 10px; +} + +.tw-modal { + z-index: 1200 !important; + max-height: 100dvh; +} + +.tw-modal-box { + max-height: calc(100dvh - 2em); +} + +.tw-tab-content .container { + height: 100%; +} \ No newline at end of file diff --git a/src/assets/css/toastify.css b/src/assets/css/toastify.css new file mode 100644 index 00000000..aa235288 --- /dev/null +++ b/src/assets/css/toastify.css @@ -0,0 +1,26 @@ +:root { + --toastify-color-info: theme('colors.info'); + --toastify-color-success: theme('colors.success'); + --toastify-color-warning: theme('colors.warning'); + --toastify-color-error: theme('colors.error'); +} + +.Toastify__toast { + border-radius: 1rem; + --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + margin-left: 1rem; + margin-right: 1rem; + margin-bottom: 1rem; + background-color: theme('colors.base-100'); + color: theme('colors.base-content'); +} + +.Toastify__toast-container { + z-index: 2001 !important; +} + +.Toastify__toast-container--top-right { + top: 4.75em !important; +} \ No newline at end of file diff --git a/src/css.tsx b/src/css.tsx new file mode 100644 index 00000000..5856b54a --- /dev/null +++ b/src/css.tsx @@ -0,0 +1,15 @@ +import 'leaflet/dist/leaflet.css' +import 'leaflet.locatecontrol/dist/L.Control.Locate.css' +import 'react-image-crop/dist/ReactCrop.css' +import 'react-photo-album/rows.css' +import 'react-toastify/dist/ReactToastify.css' +import 'yet-another-react-lightbox/styles.css' + +import '#assets/css/tailwind.css' +import '#assets/css/masonry.css' +import '#assets/css/toastify.css' +import '#assets/css/custom-file-upload.css' +import '#assets/css/misc.css' +import '#assets/css/marker-icons.css' +import '#assets/css/leaflet.css' +import '#assets/css/color-picker.css' diff --git a/src/index.css b/src/index.css deleted file mode 100644 index 0790b43c..00000000 --- a/src/index.css +++ /dev/null @@ -1,105 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -.fade { - mask-image: linear-gradient(180deg, transparent, #000 1%, #000 99%, transparent); -} - -.tw-modal { - z-index: 1200 !important; -} - -.tw-menu li a { - border-radius: 10px; -} - -.tw-modal { - z-index: 1200 !important; - max-height: 100dvh; -} - -.tw-modal-box { - max-height: calc(100dvh - 2em); -} - -.Toastify__toast { - border-radius: 1rem; - --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - margin-left: 1rem; - margin-right: 1rem; - margin-bottom: 1rem; - background-color: theme('colors.base-100'); - color: theme('colors.base-content'); -} - -.Toastify__toast-container { - z-index: 2001 !important; -} - -.Toastify__toast-container--top-right { - top: 4.75em !important; -} - -:root { - - --toastify-color-info: theme('colors.info'); - --toastify-color-success: theme('colors.success'); - --toastify-color-warning: theme('colors.warning'); - --toastify-color-error: theme('colors.error'); - -} - -.placeholder-center::placeholder { - text-align: center; -} - -.custom-file-upload { - cursor: pointer; -} - -input[type="file"] { - display: none; -} - -.custom-file-upload:hover .button { - opacity: 0.8; -} - -.custom-file-upload .button { - transition: .5s ease; - opacity: 0; - position: absolute; - transform: translate(8px, 8px); - -} - -.tw-tab-content .container { - height: 100%; -} - -.masonry { - column-count: 1; - column-gap: 1.5rem; -} -.masonry-item { - break-inside: avoid; - margin-bottom: 1.5rem; -} -@media (min-width: 640px) { - .masonry { - column-count: 2; - } -} -@media (min-width: 1024px) { - .masonry { - column-count: 3; - } -} -@media (min-width: 1536px) { - .masonry { - column-count: 4; - } -} \ No newline at end of file diff --git a/src/index.tsx b/src/index.tsx index 0e6c5864..b84d77a2 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,4 +1,5 @@ -import './index.css' +// eslint-disable-next-line import/no-unassigned-import +import './css' export * from './Components/Map' export * from './Components/AppShell' From 5c18ed2abdab3624f10c7e4225daa50b05e3578e Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Mon, 3 Mar 2025 20:58:04 +0100 Subject: [PATCH 02/13] fix types - components/templates (#172) Fix more types - specifically in components/templates. This is done by removing eslint-ignores and fixing them. --- src/Components/Templates/DateUserInfo.tsx | 6 ++---- src/Components/Templates/EmojiPicker.tsx | 7 +++---- src/Components/Templates/ItemCard.tsx | 11 +++-------- src/Components/Templates/MapOverlayPage.tsx | 7 +++---- src/Components/Templates/OverlayItemsIndexPage.tsx | 12 ++++++------ src/Components/Templates/TagView.tsx | 4 +--- src/Components/Templates/TitleCard.tsx | 8 +++----- src/Components/Typography/ErrorText.tsx | 5 +---- src/Utils/RandomColor.ts | 7 +------ 9 files changed, 23 insertions(+), 44 deletions(-) diff --git a/src/Components/Templates/DateUserInfo.tsx b/src/Components/Templates/DateUserInfo.tsx index 4243a9c0..fcc4dacc 100644 --- a/src/Components/Templates/DateUserInfo.tsx +++ b/src/Components/Templates/DateUserInfo.tsx @@ -1,6 +1,3 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -/* eslint-disable @typescript-eslint/no-unnecessary-condition */ -/* eslint-disable @typescript-eslint/prefer-optional-chain */ import { useState } from 'react' import { timeAgo } from '#utils/TimeAgo' @@ -18,7 +15,8 @@ export const DateUserInfo = ({ item }: { item: Item }) => {

setInfoExpanded(false)} - >{`${item.date_updated && item.date_updated !== item.date_created ? 'updated' : 'posted'} ${item && item.user_created && item.user_created.first_name ? `by ${item.user_created.first_name}` : ''} ${item.date_updated ? timeAgo(item.date_updated) : timeAgo(item.date_created!)}`}

+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + >{`${item.date_updated && item.date_updated !== item.date_created ? 'updated' : 'posted'} ${item.user_created?.first_name ? `by ${item.user_created.first_name}` : ''} ${item.date_updated ? timeAgo(item.date_updated) : timeAgo(item.date_created!)}`}

) : (

selectEmoji(emoji)} - className={`tw-cursor-pointer tw-text-2xl tw-p-2 hover:tw-bg-base-200 tw-rounded-md ${emoji === selectedEmoji && 'tw-bg-base-300'}`} + className={`tw-cursor-pointer tw-text-2xl tw-p-2 hover:tw-bg-base-200 tw-rounded-md ${emoji === selectedEmoji ? 'tw-bg-base-300' : ''}`} > {emoji} @@ -121,7 +120,7 @@ export const EmojiPicker = ({ {shapes.map((shape) => (

selectShape(shape)} >
@@ -133,7 +132,7 @@ export const EmojiPicker = ({ {colors.map((color) => (
selectColor(color)} >
diff --git a/src/Components/Templates/ItemCard.tsx b/src/Components/Templates/ItemCard.tsx index b876f670..f173124f 100644 --- a/src/Components/Templates/ItemCard.tsx +++ b/src/Components/Templates/ItemCard.tsx @@ -1,8 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unnecessary-condition */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/restrict-template-expressions */ -/* eslint-disable @typescript-eslint/no-explicit-any */ import { useNavigate } from 'react-router-dom' import { StartEndView, TextView } from '#components/Map' @@ -22,7 +17,7 @@ export const ItemCard = ({ i: Item loading: boolean url: string - deleteCallback: any + deleteCallback: (item: Item) => void }) => { const navigate = useNavigate() const windowDimensions = useWindowDimensions() @@ -34,8 +29,8 @@ export const ItemCard = ({ // We could have an onClick callback instead const params = new URLSearchParams(window.location.search) if (windowDimensions.width < 786 && i.position) - navigate('/' + i.id + `${params ? `?${params}` : ''}`) - else navigate(url + i.id + `${params ? `?${params}` : ''}`) + navigate('/' + i.id + `${params.size > 0 ? `?${params.toString()}` : ''}`) + else navigate(url + i.id + `${params.size > 0 ? `?${params.toString()}` : ''}`) }} > +
{children} diff --git a/src/Components/AppShell/SideBar.tsx b/src/Components/AppShell/SideBar.tsx index 94782f3c..4ea07200 100644 --- a/src/Components/AppShell/SideBar.tsx +++ b/src/Components/AppShell/SideBar.tsx @@ -1,8 +1,8 @@ import ChevronRightIcon from '@heroicons/react/24/outline/ChevronRightIcon' -import { useRef, useState, useEffect } from 'react' +import { useState, useEffect } from 'react' import { NavLink, useLocation } from 'react-router-dom' -import { Sidenav, initTE } from 'tw-elements' +import { useAppState, useSetAppState } from './hooks/useAppState' import SidebarSubmenu from './SidebarSubmenu' export interface Route { @@ -13,40 +13,12 @@ export interface Route { blank?: boolean } -interface SidenavType extends HTMLElement { - toggleSlim(): void - toggle(): void -} - /** * @category AppShell */ export function SideBar({ routes, bottomRoutes }: { routes: Route[]; bottomRoutes?: Route[] }) { - // prevent react18 from calling useEffect twice - const init = useRef(false) - const location = useLocation() - const [instance, setInstance] = useState() - const [slim, setSlim] = useState(false) - - const toggleSlim = () => { - setSlim(!slim) - instance?.toggleSlim() - } - - useEffect(() => { - if (!init.current) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call - initTE({ Sidenav }) - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call - const instance = Sidenav.getInstance(document.getElementById('sidenav')) as SidenavType - setInstance(instance) - instance.toggleSlim() - init.current = true - } - }, []) - const [embedded, setEmbedded] = useState(true) useEffect(() => { @@ -57,18 +29,25 @@ export function SideBar({ routes, bottomRoutes }: { routes: Route[]; bottomRoute const params = new URLSearchParams(window.location.search) + const appState = useAppState() + const setAppState = useSetAppState() + + const toggleSidebarOpen = () => { + setAppState({ sideBarOpen: !appState.sideBarOpen }) + } + + const toggleSidebarSlim = () => { + setAppState({ sideBarSlim: !appState.sideBarSlim }) + } + return (
diff --git a/src/Components/AppShell/SidebarSubmenu.tsx b/src/Components/AppShell/SidebarSubmenu.tsx index 1c12e851..347d1323 100644 --- a/src/Components/AppShell/SidebarSubmenu.tsx +++ b/src/Components/AppShell/SidebarSubmenu.tsx @@ -32,13 +32,7 @@ function SidebarSubmenu({
{/** Route header */}
setIsExpanded(!isExpanded)}> - {icon}{' '} - - {name}{' '} - + {icon} {name} {/** Submenu list */} -
+
    {submenu?.map((m, k) => { return ( diff --git a/src/Components/AppShell/hooks/useAppState.tsx b/src/Components/AppShell/hooks/useAppState.tsx index c338d8c4..bdd94859 100644 --- a/src/Components/AppShell/hooks/useAppState.tsx +++ b/src/Components/AppShell/hooks/useAppState.tsx @@ -6,14 +6,16 @@ import type { AssetsApi } from '#types/AssetsApi' interface AppState { assetsApi: AssetsApi - userType: string + sideBarOpen: boolean + sideBarSlim: boolean } type UseAppManagerResult = ReturnType const initialAppState: AppState = { assetsApi: {} as AssetsApi, - userType: '', + sideBarOpen: false, + sideBarSlim: false, } const AppContext = createContext({ diff --git a/src/Components/AppShell/hooks/useAssets.tsx b/src/Components/AppShell/hooks/useAssets.tsx deleted file mode 100644 index 6c04d6ab..00000000 --- a/src/Components/AppShell/hooks/useAssets.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* eslint-disable react/prop-types */ - -/* eslint-disable @typescript-eslint/no-empty-function */ -import { useCallback, useState, createContext, useContext } from 'react' - -import type { AssetsApi } from '#types/AssetsApi' - -type UseAssetManagerResult = ReturnType - -const AssetContext = createContext({ - api: {} as AssetsApi, - setAssetsApi: () => {}, -}) - -function useAssetsManager(): { - api: AssetsApi - setAssetsApi: (api: AssetsApi) => void -} { - const [api, setApi] = useState({} as AssetsApi) - - const setAssetsApi = useCallback((api: AssetsApi) => { - setApi(api) - }, []) - - return { api, setAssetsApi } -} - -export const AssetsProvider: React.FunctionComponent<{ - children?: React.ReactNode -}> = ({ children }) => ( - {children} -) - -export const useAssetApi = (): AssetsApi => { - const { api } = useContext(AssetContext) - return api -} - -export const useSetAssetApi = (): UseAssetManagerResult['setAssetsApi'] => { - const { setAssetsApi } = useContext(AssetContext) - return setAssetsApi -} diff --git a/src/Components/Profile/ProfileForm.tsx b/src/Components/Profile/ProfileForm.tsx index 0b109010..6f84f689 100644 --- a/src/Components/Profile/ProfileForm.tsx +++ b/src/Components/Profile/ProfileForm.tsx @@ -5,7 +5,6 @@ import { useEffect, useState } from 'react' import { useLocation, useNavigate } from 'react-router-dom' import { toast } from 'react-toastify' -import { useAppState } from '#components/AppShell/hooks/useAppState' import { useAuth } from '#components/Auth/useAuth' import { useItems, useUpdateItem, useAddItem } from '#components/Map/hooks/useItems' import { useLayers } from '#components/Map/hooks/useLayers' @@ -62,7 +61,6 @@ export function ProfileForm() { const hasUserPermission = useHasUserPermission() const getItemTags = useGetItemTags() const items = useItems() - const appState = useAppState() const [urlParams, setUrlParams] = useState(new URLSearchParams(location.search)) @@ -146,8 +144,12 @@ export function ProfileForm() { const [template, setTemplate] = useState('') useEffect(() => { - setTemplate(item.layer?.itemType.template ?? appState.userType) - }, [appState.userType, item]) + if (item.layer?.itemType.template) setTemplate(item.layer?.itemType.template) + else { + const userLayer = layers.find((l) => l.userProfileLayer === true) + if (userLayer) setTemplate(userLayer.itemType.template) + } + }, [item, layers]) return ( <> diff --git a/src/Components/Profile/ProfileView.tsx b/src/Components/Profile/ProfileView.tsx index dd907a63..bc16e20d 100644 --- a/src/Components/Profile/ProfileView.tsx +++ b/src/Components/Profile/ProfileView.tsx @@ -12,9 +12,9 @@ import { useEffect, useState } from 'react' import { useMap } from 'react-leaflet' import { useLocation, useNavigate } from 'react-router-dom' -import { useAppState } from '#components/AppShell/hooks/useAppState' import { useClusterRef } from '#components/Map/hooks/useClusterRef' import { useItems, useRemoveItem, useUpdateItem } from '#components/Map/hooks/useItems' +import { useLayers } from '#components/Map/hooks/useLayers' import { useLeafletRefs } from '#components/Map/hooks/useLeafletRefs' import { useHasUserPermission } from '#components/Map/hooks/usePermissions' import { useSelectPosition, useSetSelectPosition } from '#components/Map/hooks/useSelectPosition' @@ -57,7 +57,7 @@ export function ProfileView({ attestationApi }: { attestationApi?: ItemsApi const setSelectPosition = useSetSelectPosition() const clusterRef = useClusterRef() const leafletRefs = useLeafletRefs() - const appState = useAppState() + const layers = useLayers() const [attestations, setAttestations] = useState([]) @@ -162,8 +162,12 @@ export function ProfileView({ attestationApi }: { attestationApi?: ItemsApi }, [selectPosition]) useEffect(() => { - setTemplate(item?.layer?.itemType.template ?? appState.userType) - }, [appState.userType, item]) + if (item?.layer?.itemType.template) setTemplate(item.layer.itemType.template) + else { + const userLayer = layers.find((l) => l.userProfileLayer === true) + if (userLayer) setTemplate(userLayer.itemType.template) + } + }, [item, layers]) return ( <> diff --git a/src/Components/Profile/Templates/TabsView.tsx b/src/Components/Profile/Templates/TabsView.tsx index c2bdcb93..fa045374 100644 --- a/src/Components/Profile/Templates/TabsView.tsx +++ b/src/Components/Profile/Templates/TabsView.tsx @@ -51,9 +51,7 @@ export const TabsView = ({ const items = useItems() const appState = useAppState() const getUserProfile = (id: string) => { - return items.find( - (i) => i.user_created?.id === id && i.layer?.itemType.name === appState.userType, - ) + return items.find((i) => i.user_created?.id === id && i.layer?.userProfileLayer) } useEffect(() => { diff --git a/tailwind.config.js b/tailwind.config.js index 30ebd8ee..c7c62895 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -64,8 +64,8 @@ module.exports = { pulseGrow: 'pulseGrow 2s ease-in-out infinite', }, }, - // eslint-disable-next-line import/no-commonjs, import/extensions - plugins: [require('daisyui'), require('tw-elements/dist/plugin.cjs')], + // eslint-disable-next-line import/no-commonjs + plugins: [require('daisyui')], daisyui: { themes: [ 'light', From 0678506ed6d6f1aca4c8afe2ca1b599ed155c6ea Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 5 Mar 2025 00:54:15 +0100 Subject: [PATCH 04/13] fix(workflow): unit tests workflow not running properly (#178) * workflow: unit tests do not run properly The pedicate-quantifier every seem not to mach properly Problematic worklfow: https://github.com/utopia-os/utopia-ui/actions/runs/13639312728/job/38125326624 The PR(https://github.com/utopia-os/utopia-ui/pull/172) did not execute, but tsx files were changed. * reduce coverage requirements This was inherited frommaster --- .github/workflows/test.unit.yml | 2 -- vite.config.ts | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.unit.yml b/.github/workflows/test.unit.yml index 8b4a5fd3..90d91a99 100644 --- a/.github/workflows/test.unit.yml +++ b/.github/workflows/test.unit.yml @@ -17,8 +17,6 @@ jobs: unit: - '.github/workflows/**/*' - '**/*' - - '!**/*.md' - predicate-quantifier: 'every' unit: if: needs.files-changed.outputs.unit == 'true' diff --git a/vite.config.ts b/vite.config.ts index d596e603..6745b480 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -16,8 +16,8 @@ export default defineConfig({ reporter: ['html', 'json-summary'], thresholds: { lines: 1, - functions: 59, - branches: 62, + functions: 56, + branches: 58, statements: 1, }, }, From 6a5bc0ade3dece62e6726f388c18f710dce62cde Mon Sep 17 00:00:00 2001 From: Anton Tranelis <31516529+antontranelis@users.noreply.github.com> Date: Wed, 5 Mar 2025 14:51:56 +0000 Subject: [PATCH 05/13] removed hardcoded asset api (#179) --- src/Components/AppShell/NavBar.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Components/AppShell/NavBar.tsx b/src/Components/AppShell/NavBar.tsx index b74b69ad..593f6d39 100644 --- a/src/Components/AppShell/NavBar.tsx +++ b/src/Components/AppShell/NavBar.tsx @@ -33,8 +33,6 @@ export default function NavBar({ appName }: { appName: string }) { : setUserProfile({ id: crypto.randomUUID(), name: user?.first_name ?? '', text: '' }) }, [user, items]) - // useEffect(() => {}, [userProfile]) - const nameRef = useRef(null) const [nameWidth, setNameWidth] = useState(0) const location = useLocation() @@ -111,7 +109,7 @@ export default function NavBar({ appName }: { appName: string }) { {userProfile.image && (
    - +
    )} From 77f596fd76c5b2d00042163516a103a405c67577 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 5 Mar 2025 22:23:43 +0100 Subject: [PATCH 06/13] Remove unused file (#183) --- src/Components/Map/setItemLocation.tsx | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/Components/Map/setItemLocation.tsx diff --git a/src/Components/Map/setItemLocation.tsx b/src/Components/Map/setItemLocation.tsx deleted file mode 100644 index ae776994..00000000 --- a/src/Components/Map/setItemLocation.tsx +++ /dev/null @@ -1,10 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ - -import { useMap } from 'react-leaflet' - -export const setItemLocation = () => { - // eslint-disable-next-line react-hooks/rules-of-hooks - const map = useMap() - - return
    -} From 31f0dd7a8185c533843e61eb302e46b4a6952539 Mon Sep 17 00:00:00 2001 From: Anton Tranelis <31516529+antontranelis@users.noreply.github.com> Date: Wed, 5 Mar 2025 21:26:16 +0000 Subject: [PATCH 07/13] fix(source): fixed attestation layout (#180) * fixed attestation layout * fixed for attestations on other map instances --------- Co-authored-by: Ulf Gebhardt --- src/Components/Profile/Templates/TabsView.tsx | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/Components/Profile/Templates/TabsView.tsx b/src/Components/Profile/Templates/TabsView.tsx index fa045374..bec02e24 100644 --- a/src/Components/Profile/Templates/TabsView.tsx +++ b/src/Components/Profile/Templates/TabsView.tsx @@ -150,29 +150,41 @@ export const TabsView = ({
- -
-
-
- Avatar + {getUserProfile(a.user_created.id) ? ( + +
+
+
+ {getUserProfile(a.user_created.id)?.image && ( + Avatar + )} +
+
+
+
+ {getUserProfile(a.user_created.id)?.name ?? + a.user_created.first_name}{' '} +
+
+ {timeAgo(a.date_created)} +
-
-
- {getUserProfile(a.user_created.id)?.name} -
-
- {timeAgo(a.date_created)} -
+ + ) : ( +
+
{a.user_created.first_name}
+
+ {timeAgo(a.date_created)}
- + )} ))} From 9f631f156c0e99aa3940bab28240f9d8b95634e6 Mon Sep 17 00:00:00 2001 From: Anton Tranelis <31516529+antontranelis@users.noreply.github.com> Date: Wed, 5 Mar 2025 21:31:57 +0000 Subject: [PATCH 08/13] fix(source): fix avatar bug (#173) * rollup - fail when typescript has warnings or errors Currently this is detected when building the docu. Since the developer rarely does that the problem is detected on github. This change allows the developer to discover the error early by failing the build. * 3.0.75 * fix avatar disapeared when item is updated * fixed linting --------- Co-authored-by: Ulf Gebhardt --- .../Map/Subcomponents/ItemPopupComponents/HeaderView.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx b/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx index 835da429..69f7569e 100644 --- a/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx +++ b/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx @@ -12,7 +12,7 @@ import EllipsisVerticalIcon from '@heroicons/react/16/solid/EllipsisVerticalIcon' import PencilIcon from '@heroicons/react/24/solid/PencilIcon' import TrashIcon from '@heroicons/react/24/solid/TrashIcon' -import { useState, useEffect } from 'react' +import { useState } from 'react' import { useNavigate } from 'react-router-dom' import TargetDotSVG from '#assets/targetDot.svg' @@ -56,10 +56,6 @@ export function HeaderView({ const [imageLoaded, setImageLoaded] = useState(false) - useEffect(() => { - setImageLoaded(false) - }, [item]) - const avatar = item.image && appState.assetsApi.url + item.image + `${big ? '?width=160&heigth=160' : '?width=80&heigth=80'}` From a412895d5d4f46c094d824c981f3833acabd2c43 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 6 Mar 2025 00:42:02 +0100 Subject: [PATCH 09/13] Simplify the ContextWrapper (#182) Co-authored-by: Anton Tranelis <31516529+antontranelis@users.noreply.github.com> --- src/Components/AppShell/ContextWrapper.tsx | 42 ++++++---------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/src/Components/AppShell/ContextWrapper.tsx b/src/Components/AppShell/ContextWrapper.tsx index ece603ad..67620cdf 100644 --- a/src/Components/AppShell/ContextWrapper.tsx +++ b/src/Components/AppShell/ContextWrapper.tsx @@ -1,6 +1,6 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { useContext, createContext } from 'react' -import { BrowserRouter as Router, useLocation } from 'react-router-dom' +import { BrowserRouter as Router, useInRouterContext } from 'react-router-dom' import { ToastContainer } from 'react-toastify' import { QuestsProvider } from '#components/Gaming/hooks/useQuests' @@ -21,43 +21,23 @@ const ContextCheckContext = createContext(false) export const ContextWrapper = ({ children }: { children: React.ReactNode }) => { const isWrapped = useContext(ContextCheckContext) - // Check if we are already inside a Router - let location - try { - // eslint-disable-next-line react-hooks/rules-of-hooks - location = useLocation() - // eslint-disable-next-line no-catch-all/no-catch-all - } catch (e) { - location = null - } + const isInsideRouter = useInRouterContext() - // Case 1: Only the Router is missing, but ContextWrapper is already provided - if (!location && isWrapped) { - return {children} - } + let returnValue = children - // Case 2: Neither Router nor ContextWrapper is present - if (!location && !isWrapped) { - return ( - - - {children} - - - ) - } - - // Case 3: Only ContextWrapper is missing - if (location && !isWrapped) { - return ( + if (!isWrapped) { + returnValue = ( - {children} + {returnValue} ) } - // Case 4: Both Router and ContextWrapper are already present - return children + if (!isInsideRouter) { + returnValue = {returnValue} + } + + return returnValue } // eslint-disable-next-line react/prop-types From d987ac816a724add5bf2cfd7480f4c6c8d847078 Mon Sep 17 00:00:00 2001 From: Anton Tranelis <31516529+antontranelis@users.noreply.github.com> Date: Thu, 6 Mar 2025 10:02:55 +0000 Subject: [PATCH 10/13] docs(docu): update README.md (#181) * Update README.md * Update README.md fixed url --- examples/1-basic-map/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/1-basic-map/README.md b/examples/1-basic-map/README.md index 7b1f3b35..db387259 100644 --- a/examples/1-basic-map/README.md +++ b/examples/1-basic-map/README.md @@ -8,6 +8,7 @@ We'll use **Vite** to create an empty React app named **"1-static-map"**: ```shell npm create vite@latest 1-static-map -- --template react-ts +``` Next, we navigate into our project folder and install the [utopia-ui](https://github.com/utopia-os/utopia-ui) package: @@ -38,7 +39,8 @@ To see our **first map app**, we start the development server: ```shell npm run dev +``` -Now, we can open the project in the browser and explore our interactive map! 😊 +Now, we can open [localhost:5173](http://localhost:5173/) in the browser and explore our interactive map! 😊 ➡️ In [Example 2](../2-static-layers/), we'll add **static data** to our map. From 0595e54a9b2333e72a6aedad059f7180ef029c19 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 13 Mar 2025 19:27:56 +0100 Subject: [PATCH 11/13] Use defaultValue instead of selected (#187) --- src/Components/Input/ComboBoxInput.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Components/Input/ComboBoxInput.tsx b/src/Components/Input/ComboBoxInput.tsx index b6712a93..62711c4d 100644 --- a/src/Components/Input/ComboBoxInput.tsx +++ b/src/Components/Input/ComboBoxInput.tsx @@ -16,9 +16,10 @@ const ComboBoxInput = ({ id, options, value, onValueChange }: ComboBoxProps) => id={id} className='tw-form-select tw-block tw-w-full tw-py-2 tw-px-4 tw-border tw-border-gray-300 rounded-md tw-shadow-sm tw-text-sm focus:tw-outline-none focus:tw-ring-indigo-500 focus:tw-border-indigo-500 sm:tw-text-sm' onChange={handleChange} + defaultValue={value} > {options.map((o) => ( - ))} From 8b7cff2b322bb836ea92c5212d8cb332c9982302 Mon Sep 17 00:00:00 2001 From: Anton Tranelis <31516529+antontranelis@users.noreply.github.com> Date: Wed, 19 Mar 2025 23:07:43 +0000 Subject: [PATCH 12/13] fix(source): fix bug in ItemFormPopup (#191) * fix bug in ItemFormPopup * removed logging * removed more logging --- src/Components/Map/Subcomponents/ItemFormPopup.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Components/Map/Subcomponents/ItemFormPopup.tsx b/src/Components/Map/Subcomponents/ItemFormPopup.tsx index 5a2ad79d..534fe2fd 100644 --- a/src/Components/Map/Subcomponents/ItemFormPopup.tsx +++ b/src/Components/Map/Subcomponents/ItemFormPopup.tsx @@ -83,18 +83,13 @@ export function ItemFormPopup(props: ItemFormPopupProps) { toast.error(error.toString()) } if (success) { - // eslint-disable-next-line no-console - console.log(props.item) - updateItem({ ...props.item, ...formItem }) toast.success('Item updated') } setSpinner(false) map.closePopup() } else { - const item = items.find( - (i) => i.user_created?.id === user?.id && i.layer?.id === props.layer.id, - ) + const item = items.find((i) => i.user_created?.id === user?.id && i.layer === props.layer) const uuid = crypto.randomUUID() let success = false From 4fc9516715f7f5d2993661db3d2054148cd0a8e7 Mon Sep 17 00:00:00 2001 From: Anton Tranelis <31516529+antontranelis@users.noreply.github.com> Date: Wed, 19 Mar 2025 23:28:04 +0000 Subject: [PATCH 13/13] fix(source): external svg theming (#192) * allow include of external svgs without breaking theming * 3.0.77 * 3.0.78 * fixed LocateControl and added react-inlinesvg to external dependencies * theming toast close button * fixed typing * theming search resuts * theming search resuts * theming search resuts * theming donation widget * theming donation widget --------- Co-authored-by: Ulf Gebhardt --- package-lock.json | 24 +++++++++++-- package.json | 3 +- rollup.config.js | 1 + src/Components/AppShell/ContextWrapper.tsx | 12 +++++++ src/Components/AppShell/index.tsx | 1 + .../Map/Subcomponents/AddButton.tsx | 4 ++- .../Subcomponents/Controls/LayerControl.tsx | 3 +- .../Subcomponents/Controls/LocateControl.tsx | 4 +-- .../Subcomponents/Controls/SearchControl.tsx | 34 ++++++++++++------- .../ItemPopupComponents/HeaderView.tsx | 3 +- src/Components/Map/UtopiaMapInner.tsx | 6 ++-- src/assets/target.svg | 2 +- 12 files changed, 73 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9ae9d72a..5f2c81c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "utopia-ui", - "version": "3.0.76", + "version": "3.0.78", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "utopia-ui", - "version": "3.0.76", + "version": "3.0.78", "license": "GPL-3.0-only", "dependencies": { "@heroicons/react": "^2.0.17", @@ -18,6 +18,7 @@ "radash": "^12.1.0", "react-colorful": "^5.6.1", "react-image-crop": "^10.1.8", + "react-inlinesvg": "^4.2.0", "react-leaflet": "^4.2.1", "react-leaflet-cluster": "^2.1.0", "react-markdown": "^9.0.1", @@ -10203,6 +10204,14 @@ "react": "^18.3.1" } }, + "node_modules/react-from-dom": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/react-from-dom/-/react-from-dom-0.7.5.tgz", + "integrity": "sha512-CO92PmMKo/23uYPm6OFvh5CtZbMgHs/Xn+o095Lz/TZj9t8DSDhGdSOMLxBxwWI4sr0MF17KUn9yJWc5Q00R/w==", + "peerDependencies": { + "react": "16.8 - 19" + } + }, "node_modules/react-image-crop": { "version": "10.1.8", "resolved": "https://registry.npmjs.org/react-image-crop/-/react-image-crop-10.1.8.tgz", @@ -10212,6 +10221,17 @@ "react": ">=16.13.1" } }, + "node_modules/react-inlinesvg": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/react-inlinesvg/-/react-inlinesvg-4.2.0.tgz", + "integrity": "sha512-V59P6sFU7NACIbvoay9ikYKVFWyIIZFGd7w6YT1m+H7Ues0fOI6B6IftE6NPSYXXv7RHVmrncIyJeYurs3OJcA==", + "dependencies": { + "react-from-dom": "^0.7.5" + }, + "peerDependencies": { + "react": "16.8 - 19" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", diff --git a/package.json b/package.json index 04d945c3..ea2ee04a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "utopia-ui", - "version": "3.0.76", + "version": "3.0.78", "description": "Reuseable React Components to build mapping apps for real life communities and networks", "repository": "https://github.com/utopia-os/utopia-ui", "homepage": "https://utopia-os.org/", @@ -99,6 +99,7 @@ "radash": "^12.1.0", "react-colorful": "^5.6.1", "react-image-crop": "^10.1.8", + "react-inlinesvg": "^4.2.0", "react-leaflet": "^4.2.1", "react-leaflet-cluster": "^2.1.0", "react-markdown": "^9.0.1", diff --git a/rollup.config.js b/rollup.config.js index 05dd097b..dac65839 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -76,6 +76,7 @@ export default [ 'leaflet.locatecontrol/dist/L.Control.Locate.css', 'yet-another-react-lightbox', 'react-photo-album', + 'react-inlinesvg', ], }, { diff --git a/src/Components/AppShell/ContextWrapper.tsx b/src/Components/AppShell/ContextWrapper.tsx index 67620cdf..3eba67ee 100644 --- a/src/Components/AppShell/ContextWrapper.tsx +++ b/src/Components/AppShell/ContextWrapper.tsx @@ -15,9 +15,20 @@ import { TagsProvider } from '#components/Map/hooks/useTags' import { AppStateProvider } from './hooks/useAppState' +import type { CloseButtonProps } from 'react-toastify' + // Helper context to determine if the ContextWrapper is already present. const ContextCheckContext = createContext(false) +const CloseButton = ({ closeToast }: CloseButtonProps) => ( + +) + export const ContextWrapper = ({ children }: { children: React.ReactNode }) => { const isWrapped = useContext(ContextCheckContext) @@ -67,6 +78,7 @@ export const Wrappers = ({ children }) => { draggable pauseOnHover theme='light' + closeButton={CloseButton} /> {children} diff --git a/src/Components/AppShell/index.tsx b/src/Components/AppShell/index.tsx index d0c058df..7f27e9d5 100644 --- a/src/Components/AppShell/index.tsx +++ b/src/Components/AppShell/index.tsx @@ -1,3 +1,4 @@ export * from './AppShell' export { SideBar } from './SideBar' export { Content } from './Content' +export { default as SVG } from 'react-inlinesvg' diff --git a/src/Components/Map/Subcomponents/AddButton.tsx b/src/Components/Map/Subcomponents/AddButton.tsx index c2de677b..c1a46a54 100644 --- a/src/Components/Map/Subcomponents/AddButton.tsx +++ b/src/Components/Map/Subcomponents/AddButton.tsx @@ -1,5 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ +import SVG from 'react-inlinesvg' + import PlusSVG from '#assets/plus.svg' import { useLayers } from '#components/Map/hooks/useLayers' import { useHasUserPermission } from '#components/Map/hooks/usePermissions' @@ -31,7 +33,7 @@ export default function AddButton({ {canAddItems() ? (
    {layers.map( diff --git a/src/Components/Map/Subcomponents/Controls/LayerControl.tsx b/src/Components/Map/Subcomponents/Controls/LayerControl.tsx index 0150409a..69abc40a 100644 --- a/src/Components/Map/Subcomponents/Controls/LayerControl.tsx +++ b/src/Components/Map/Subcomponents/Controls/LayerControl.tsx @@ -1,4 +1,5 @@ import { useState } from 'react' +import SVG from 'react-inlinesvg' import LayerSVG from '#assets/layer.svg' import { useIsLayerVisible, useToggleVisibleLayer } from '#components/Map/hooks/useFilter' @@ -56,7 +57,7 @@ export function LayerControl() { setOpen(true) }} > - Layers +
)}
diff --git a/src/Components/Map/Subcomponents/Controls/LocateControl.tsx b/src/Components/Map/Subcomponents/Controls/LocateControl.tsx index db555bf2..ace5b9e0 100644 --- a/src/Components/Map/Subcomponents/Controls/LocateControl.tsx +++ b/src/Components/Map/Subcomponents/Controls/LocateControl.tsx @@ -6,6 +6,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ import { control } from 'leaflet' import { useEffect, useRef, useState } from 'react' +import SVG from 'react-inlinesvg' import { useMap, useMapEvents } from 'react-leaflet' import TargetSVG from '#assets/target.svg' @@ -58,9 +59,8 @@ export const LocateControl = () => { {loading ? ( ) : ( - x diff --git a/src/Components/Map/Subcomponents/Controls/SearchControl.tsx b/src/Components/Map/Subcomponents/Controls/SearchControl.tsx index a267019e..8b785784 100644 --- a/src/Components/Map/Subcomponents/Controls/SearchControl.tsx +++ b/src/Components/Map/Subcomponents/Controls/SearchControl.tsx @@ -15,6 +15,7 @@ import MagnifyingGlassIcon from '@heroicons/react/24/outline/MagnifyingGlassIcon import axios from 'axios' import { LatLng, LatLngBounds, marker } from 'leaflet' import { useEffect, useRef, useState } from 'react' +import SVG from 'react-inlinesvg' import { useMap, useMapEvents } from 'react-leaflet' import { useLocation, useNavigate } from 'react-router-dom' @@ -169,7 +170,7 @@ export const SearchControl = () => { {itemsResults.slice(0, 5).map((item) => (
{ const marker = Object.entries(leafletRefs).find((r) => r[1].item === item)?.[1] .marker @@ -182,18 +183,25 @@ export const SearchControl = () => { } }} > -
- { + code = code.replace(/fill=".*?"/g, 'fill="currentColor"') + code = code.replace(/stroke=".*?"/g, 'stroke="currentColor"') + return code + }} /> -
-
- {item.name} -
-
- {item.text} -
+ ) : ( +
+ )} +
+
+ {item.name} +
+
+ {item.text}
@@ -236,7 +244,7 @@ export const SearchControl = () => { hide() }} > - +
{geo?.properties.name ? geo?.properties.name : value} diff --git a/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx b/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx index 69f7569e..58690d84 100644 --- a/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx +++ b/src/Components/Map/Subcomponents/ItemPopupComponents/HeaderView.tsx @@ -13,6 +13,7 @@ import EllipsisVerticalIcon from '@heroicons/react/16/solid/EllipsisVerticalIcon import PencilIcon from '@heroicons/react/24/solid/PencilIcon' import TrashIcon from '@heroicons/react/24/solid/TrashIcon' import { useState } from 'react' +import SVG from 'react-inlinesvg' import { useNavigate } from 'react-router-dom' import TargetDotSVG from '#assets/targetDot.svg' @@ -159,7 +160,7 @@ export function HeaderView({ className='!tw-text-base-content tw-cursor-pointer' onClick={setPositionCallback} > - Position + )} diff --git a/src/Components/Map/UtopiaMapInner.tsx b/src/Components/Map/UtopiaMapInner.tsx index 25198f21..0ae8fc43 100644 --- a/src/Components/Map/UtopiaMapInner.tsx +++ b/src/Components/Map/UtopiaMapInner.tsx @@ -75,10 +75,12 @@ export function UtopiaMapInner({ , diff --git a/src/assets/target.svg b/src/assets/target.svg index 711e071b..12418655 100644 --- a/src/assets/target.svg +++ b/src/assets/target.svg @@ -5,4 +5,4 @@ xmlns='http://www.w3.org/2000/svg' > - \ No newline at end of file +