From 4041e9472ac443015d8efc87721466a9da8ec144 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Mon, 3 Mar 2025 19:42:59 +0100 Subject: [PATCH 1/4] 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 2/4] 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 4/4] 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, }, },