diff --git a/package-lock.json b/package-lock.json index fa638c8a..60489529 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@tanstack/react-query": "^5.17.8", "@types/offscreencanvas": "^2019.7.1", "axios": "^1.6.5", + "date-fns": "^3.3.1", "leaflet": "^1.9.4", "leaflet.locatecontrol": "^0.79.0", "prop-types": "^15.8.1", @@ -1308,6 +1309,15 @@ "url": "https://opencollective.com/daisyui" } }, + "node_modules/date-fns": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.3.1.tgz", + "integrity": "sha512-y8e109LYGgoQDveiEBD3DYXKba1jWf5BA8YU1FL5Tvm0BTdEfy54WLCwnuYWZNnzzvALy/QQ4Hov+Q9RVRv+Zw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", diff --git a/package.json b/package.json index 77aedba4..79b6d434 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@tanstack/react-query": "^5.17.8", "@types/offscreencanvas": "^2019.7.1", "axios": "^1.6.5", + "date-fns": "^3.3.1", "leaflet": "^1.9.4", "leaflet.locatecontrol": "^0.79.0", "prop-types": "^15.8.1", diff --git a/src/Components/Map/Subcomponents/ItemPopupComponents/TextView.tsx b/src/Components/Map/Subcomponents/ItemPopupComponents/TextView.tsx index be9445d6..3d8ddbec 100644 --- a/src/Components/Map/Subcomponents/ItemPopupComponents/TextView.tsx +++ b/src/Components/Map/Subcomponents/ItemPopupComponents/TextView.tsx @@ -9,11 +9,17 @@ import { getValue } from '../../../../Utils/GetValue'; import remarkBreaks from 'remark-breaks' import { decodeTag } from '../../../../Utils/FormatTags'; -export const TextView = ({ item, truncate = false}: { item?: Item, truncate?: boolean }) => { +export const TextView = ({ item, truncate = false, itemTextField}: { item?: Item, truncate?: boolean,itemTextField?: string }) => { const tags = useTags(); const addFilterTag = useAddFilterTag(); - let text = item?.layer?.itemTextField && item ? getValue(item, item.layer?.itemTextField) : ""; + console.log(item); + + + let text = ""; + + if(itemTextField && item) text = getValue(item, itemTextField); + else text = item?.layer?.itemTextField && item ? getValue(item, item.layer?.itemTextField) : "" if(item && text && truncate) text = truncateString(text, 100, true); diff --git a/src/Components/Profile/OverlayProfile.tsx b/src/Components/Profile/OverlayProfile.tsx index bc7d3b3a..16bfa366 100644 --- a/src/Components/Profile/OverlayProfile.tsx +++ b/src/Components/Profile/OverlayProfile.tsx @@ -31,6 +31,8 @@ export function OverlayProfile() { const [offers, setOffers] = useState>([]); const [needs, setNeeds] = useState>([]); + const [activeTab, setActiveTab] = useState(1); + const addFilterTag = useAddFilterTag(); @@ -85,8 +87,21 @@ export function OverlayProfile() { } -
-
+ + + +
+ +
+ setActiveTab(1)} /> +
+ +
+ + setActiveTab(2)} /> +
+
+
{ offers.length > 0 ?
@@ -110,7 +125,18 @@ export function OverlayProfile() {
: "" }
- +
+
+ + setActiveTab(3)} /> +
+ +
+
+ + + +
} diff --git a/src/Components/Profile/OverlayProfileSettings.tsx b/src/Components/Profile/OverlayProfileSettings.tsx index 7f5d81e9..dfdf8a79 100644 --- a/src/Components/Profile/OverlayProfileSettings.tsx +++ b/src/Components/Profile/OverlayProfileSettings.tsx @@ -30,6 +30,7 @@ export function OverlayProfileSettings() { const [color, setColor] = useState(""); const [offers, setOffers] = useState>([]); const [needs, setNeeds] = useState>([]); + const [contact, setContact] = useState(""); const [activeTab, setActiveTab] = useState(1); @@ -63,6 +64,7 @@ export function OverlayProfileSettings() { const need = tags.find(t => t.id === o.tags_id); need && setNeeds(current => [...current,need]) }) + setContact(user?.contact ? user.contact : ""); }, [user]) const imgRef = React.useRef(null) @@ -180,7 +182,7 @@ export function OverlayProfileSettings() { }); - changedUser = { id: id, first_name: name, description: text, color: color, ...avatar.length > 10 && { avatar: avatar }, ... offers.length > 0 && {offers: offer_updates}, ... needs.length > 0 && {needs: needs_updates} }; + changedUser = { id: id, first_name: name, description: text, contact: contact, color: color, ...avatar.length > 10 && { avatar: avatar }, ... offers.length > 0 && {offers: offer_updates}, ... needs.length > 0 && {needs: needs_updates} }; // update profile item in current state const item = items.find(i => i.layer?.itemOwnerField && getValue(i, i.layer?.itemOwnerField).id === id); @@ -259,9 +261,9 @@ export function OverlayProfileSettings() {
- setActiveTab(1)} /> + setActiveTab(1)} />
- setText(v)} containerStyle='tw-h-full' inputStyle='tw-h-full tw-border-t-0 tw-rounded-tl-none' /> + setText(v)} containerStyle='tw-h-full' inputStyle='tw-h-full tw-border-t-0 tw-rounded-tl-none' />
setActiveTab(2)} /> @@ -277,16 +279,8 @@ export function OverlayProfileSettings() {
setActiveTab(3)} /> -
-
- - - - - - - -
+
+ setContact(v)} containerStyle='tw-h-full' inputStyle='tw-h-full tw-border-t-0 tw-rounded-tl-none' />
diff --git a/src/Components/Templates/CircleLayout.tsx b/src/Components/Templates/CircleLayout.tsx new file mode 100644 index 00000000..ad659826 --- /dev/null +++ b/src/Components/Templates/CircleLayout.tsx @@ -0,0 +1,33 @@ +import * as React from 'react'; +import { useEffect, useRef } from 'react'; + +export const CircleLayout = ({ items,radius, fontSize }) => { + const containerRef = useRef(null); + + useEffect(() => { + const container = containerRef.current; + const itemCount = items.length; + + if (container) { + for (let i = 0; i < itemCount; i++) { + const startAngle = (Math.PI) / 2; + const angle = startAngle + (i / itemCount) * (2 * Math.PI); + const x = radius * Math.cos(angle); + const y = radius * Math.sin(angle); + const child = container.children[i] as HTMLElement; + child.style.transform = `translate(${x}px, ${y}px)`; + } + } + }, [items]); + + return ( +
+ {items.map((item, index) => ( +
+ {item} +
+ ))} +
+ ); +}; + diff --git a/src/Components/Templates/MapOverlayPage.tsx b/src/Components/Templates/MapOverlayPage.tsx index fac231d1..6ddd78cf 100644 --- a/src/Components/Templates/MapOverlayPage.tsx +++ b/src/Components/Templates/MapOverlayPage.tsx @@ -13,6 +13,8 @@ export function MapOverlayPage({ children, className, backdrop }: { children: Re const navigate = useNavigate(); const overlayRef = React.createRef() + const backdropRef = React.createRef() + React.useEffect(() => { @@ -20,12 +22,16 @@ export function MapOverlayPage({ children, className, backdrop }: { children: Re L.DomEvent.disableClickPropagation(overlayRef.current) L.DomEvent.disableScrollPropagation(overlayRef.current) } - }, [overlayRef]) + if(backdropRef.current !== null && backdrop) { + L.DomEvent.disableClickPropagation(backdropRef.current) + L.DomEvent.disableScrollPropagation(backdropRef.current) + } + }, [overlayRef, backdropRef]) return (
-
+
{children} diff --git a/src/Components/Templates/MoonCalendar.tsx b/src/Components/Templates/MoonCalendar.tsx new file mode 100644 index 00000000..6dd225e8 --- /dev/null +++ b/src/Components/Templates/MoonCalendar.tsx @@ -0,0 +1,95 @@ +import * as React from 'react' +import { useState } from 'react' +import { + add, + addDays, + eachDayOfInterval, + endOfMonth, + endOfWeek, + format, + getDay, + isSameMonth, + isToday, + parse, + startOfToday, + startOfWeek, + sub, +} from "date-fns"; +import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/outline'; +import { MapOverlayPage } from './MapOverlayPage'; +import { CircleLayout } from './CircleLayout'; +import { LUNAR_MONTH, getLastNewMoon, getNextNewMoon } from '../../Utils/Moon'; + + +export const MoonCalendar = () => { + const today = startOfToday(); + const days = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"]; + const colStartClasses = [ + "", + "col-start-2", + "col-start-3", + "col-start-4", + "col-start-5", + "col-start-6", + "col-start-7", + ]; + + const [currMonth, setCurrMonth] = useState(() => format(today, "MMM-yyyy")); + let firstDayOfMonth = parse(currMonth, "MMM-yyyy", new Date()); + + const daysInMonth = eachDayOfInterval({ + start: firstDayOfMonth, + end: endOfMonth(firstDayOfMonth), + }); + + const currentMoonCycle = eachDayOfInterval({ + start: getLastNewMoon(), + end: getNextNewMoon() + }); + + + const getPrevMonth = (event: React.MouseEvent) => { + event.preventDefault(); + const firstDayOfPrevMonth = add(firstDayOfMonth, { months: -1 }); + setCurrMonth(format(firstDayOfPrevMonth, "MMM-yyyy")); + }; + + const getNextMonth = (event: React.MouseEvent) => { + event.preventDefault(); + const firstDayOfNextMonth = add(firstDayOfMonth, { months: 1 }); + setCurrMonth(format(firstDayOfNextMonth, "MMM-yyyy")); + }; + + return ( + +

Moon Cycle

+
+ + +
+
+ +

from {format(getLastNewMoon(), "dd.MM")} - to {format(getNextNewMoon(), "dd.MM")}

+ + +
+ + +
+ ); +} + +const capitalizeFirstLetter = (string: string) => { + return string +} \ No newline at end of file diff --git a/src/Components/Templates/index.tsx b/src/Components/Templates/index.tsx index 9c08cb10..9f4824de 100644 --- a/src/Components/Templates/index.tsx +++ b/src/Components/Templates/index.tsx @@ -1,3 +1,5 @@ export {CardPage} from './CardPage' export {TitleCard} from './TitleCard' -export {MapOverlayPage} from './MapOverlayPage' \ No newline at end of file +export {MapOverlayPage} from './MapOverlayPage' +export {CircleLayout} from './CircleLayout' +export {MoonCalendar} from './MoonCalendar' \ No newline at end of file diff --git a/src/Utils/Moon.ts b/src/Utils/Moon.ts new file mode 100644 index 00000000..a9538496 --- /dev/null +++ b/src/Utils/Moon.ts @@ -0,0 +1,32 @@ +export const LUNAR_MONTH: number = 29.530588853; + +const getJulianDate = (date: Date = new Date()): number => { + const time: number = date.getTime(); + const tzoffset: number = date.getTimezoneOffset(); + return (time / 86400000) - (tzoffset / 1440) + 2440587.5; +}; + +const normalize = (value: number): number => { + value = value - Math.floor(value); + if (value < 0) value += 1; + return value; +}; + +const getLunarAgePercent = (date: Date = new Date()): number => { + return normalize((getJulianDate(date) - 2451550.1) / LUNAR_MONTH); +}; + +const getLunarAge = (date: Date = new Date()): number => { + const percent: number = getLunarAgePercent(date); + return percent * LUNAR_MONTH; +}; + +export const getNextNewMoon = (date: Date = new Date()): Date => { + const lunarAge: number = getLunarAge(date); + return new Date(getLastNewMoon().getTime() + LUNAR_MONTH * 86400000); +} + +export const getLastNewMoon = (date: Date = new Date()):Date => { + const lunarAge: number = getLunarAge(date); + return new Date(date.getTime() - lunarAge * 86400000); +} \ No newline at end of file diff --git a/src/index.css b/src/index.css index 329ba0f8..fee0798f 100644 --- a/src/index.css +++ b/src/index.css @@ -3,7 +3,7 @@ @tailwind utilities; .fade { - mask-image: linear-gradient(180deg,transparent, #000 3%, #000 97%, transparent); + mask-image: linear-gradient(180deg, transparent, #000 3%, #000 97%, transparent); } .tw-modal { @@ -52,7 +52,7 @@ } -.custom-file-upload{ +.custom-file-upload { cursor: pointer; } @@ -60,11 +60,11 @@ input[type="file"] { display: none; } -.custom-file-upload:hover .button{ +.custom-file-upload:hover .button { opacity: 0.8; } -.custom-file-upload .button{ +.custom-file-upload .button { transition: .5s ease; opacity: 0; position: absolute; @@ -74,4 +74,4 @@ input[type="file"] { .tw-tab-content .container { height: 100%; -} +} \ No newline at end of file diff --git a/src/index.tsx b/src/index.tsx index 4f753a11..d8bc55d2 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,7 +3,7 @@ export {AppShell, Content, SideBar} from "./Components/AppShell" export {AuthProvider, useAuth, LoginPage, SignupPage, RequestPasswordPage, SetNewPasswordPage} from "./Components/Auth" export {UserSettings, ProfileSettings, OverlayProfile, OverlayProfileSettings, OverlayUserSettings} from './Components/Profile' export {Quests, Modal} from './Components/Gaming' -export {TitleCard, CardPage, MapOverlayPage} from './Components/Templates' +export {TitleCard, CardPage, MapOverlayPage, CircleLayout, MoonCalendar} from './Components/Templates' export {TextInput, TextAreaInput, SelectBox} from './Components/Input' import "./index.css"