mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-12 23:36:00 +00:00
fix(source): update tailwind and daisyui (#196)
* removed daisy from config * removed tw-elements artefact * removed comments from tailwind config * removed safelist * migrated to tailwind4 and daisyui5 * deleted tailwind.config.js which is not eeded anymore * 3.0.79 * version number * fixed broken layouts * more fixing * more layout fixing * tested theming * small fixes * adapt snapshots to changes * package.json: add unit test update script * more ui refactoring & theme controller * ui improvements * package-lock.json * fix linting * fixed tabs * fix linting * fixed typing --------- Co-authored-by: mahula <lenzmath@posteo.de>
This commit is contained in:
parent
67a5e6e22d
commit
9e6bcf1846
1332
package-lock.json
generated
1332
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -39,6 +39,7 @@
|
||||
"@rollup/plugin-alias": "^5.1.1",
|
||||
"@rollup/plugin-node-resolve": "^16.0.0",
|
||||
"@rollup/plugin-typescript": "^12.1.2",
|
||||
"@tailwindcss/postcss": "^4.0.14",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.2.0",
|
||||
"@types/geojson": "^7946.0.14",
|
||||
@ -50,9 +51,8 @@
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"@vitest/coverage-v8": "^3.0.5",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"cypress": "^14.0.3",
|
||||
"daisyui": "^4.6.1",
|
||||
"daisyui": "^5.0.6",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-config-standard": "^17.1.0",
|
||||
@ -77,7 +77,7 @@
|
||||
"rollup-plugin-dts": "^6.1.1",
|
||||
"rollup-plugin-postcss": "^4.0.2",
|
||||
"rollup-plugin-svg": "^2.0.0",
|
||||
"tailwindcss": "^3.3.1",
|
||||
"tailwindcss": "^4.0.14",
|
||||
"typedoc": "^0.27.6",
|
||||
"typedoc-plugin-coverage": "^3.4.1",
|
||||
"typedoc-plugin-missing-exports": "^3.1.0",
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
// eslint-disable-next-line import/no-commonjs
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
}
|
||||
|
||||
@ -55,11 +55,9 @@ export default [
|
||||
'react-toastify',
|
||||
'react-string-replace',
|
||||
'react-toastify/dist/ReactToastify.css',
|
||||
'tw-elements',
|
||||
'react-router-dom',
|
||||
'react-leaflet-cluster',
|
||||
'@tanstack/react-query',
|
||||
'tributejs',
|
||||
'prop-types',
|
||||
'leaflet/dist/leaflet.css',
|
||||
'@heroicons/react/20/solid',
|
||||
|
||||
@ -24,14 +24,14 @@ export function AppShell({
|
||||
}) {
|
||||
return (
|
||||
<ContextWrapper>
|
||||
<div className='tw-flex tw-flex-col tw-h-full'>
|
||||
<div className='tw:flex tw:flex-col tw:h-full'>
|
||||
<SetAppState
|
||||
assetsApi={assetsApi}
|
||||
embedded={embedded}
|
||||
openCollectiveApiKey={openCollectiveApiKey}
|
||||
/>
|
||||
<NavBar appName={appName}></NavBar>
|
||||
<div id='app-content' className='tw-flex'>
|
||||
<div id='app-content' className='tw:flex'>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -12,7 +12,7 @@ export function Content({ children }: ContentProps) {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${appState.sideBarOpen && !appState.sideBarSlim ? 'tw-ml-48' : appState.sideBarOpen && appState.sideBarSlim ? 'tw-ml-14' : ''} tw-w-full tw-h-full tw-bg-base-100 tw-relative tw-transition-all tw-duration-300`}
|
||||
className={`${appState.sideBarOpen && !appState.sideBarSlim ? 'tw:ml-48' : appState.sideBarOpen && appState.sideBarSlim ? 'tw:ml-14' : ''} tw:w-full tw:h-full tw:bg-base-200 tw:relative tw:transition-all tw:duration-300`}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@ -22,7 +22,7 @@ const ContextCheckContext = createContext(false)
|
||||
|
||||
const CloseButton = ({ closeToast }: CloseButtonProps) => (
|
||||
<button
|
||||
className='tw-btn tw-btn-sm tw-btn-circle tw-btn-ghost tw-absolute tw-right-2 tw-top-2 focus:tw-outline-none'
|
||||
className='tw:btn tw:btn-sm tw:btn-circle tw:btn-ghost tw:absolute tw:right-2 tw:top-2 tw:focus:outline-hidden'
|
||||
onClick={closeToast}
|
||||
>
|
||||
✕
|
||||
|
||||
@ -1,23 +1,14 @@
|
||||
import Bars3Icon from '@heroicons/react/16/solid/Bars3Icon'
|
||||
import EllipsisVerticalIcon from '@heroicons/react/16/solid/EllipsisVerticalIcon'
|
||||
import QuestionMarkIcon from '@heroicons/react/24/outline/QuestionMarkCircleIcon'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import { useAuth } from '#components/Auth/useAuth'
|
||||
import { useItems } from '#components/Map/hooks/useItems'
|
||||
import { ThemeControl } from '#components/Templates/ThemeControl'
|
||||
|
||||
import { useAppState, useSetAppState } from './hooks/useAppState'
|
||||
|
||||
import type { Item } from '#types/Item'
|
||||
import { UserControl } from './UserControl'
|
||||
|
||||
export default function NavBar({ appName }: { appName: string }) {
|
||||
const { isAuthenticated, user, logout } = useAuth()
|
||||
|
||||
const [userProfile, setUserProfile] = useState<Item>({} as Item)
|
||||
const items = useItems()
|
||||
|
||||
const appState = useAppState()
|
||||
const setAppState = useSetAppState()
|
||||
|
||||
@ -25,14 +16,6 @@ export default function NavBar({ appName }: { appName: string }) {
|
||||
setAppState({ sideBarOpen: !appState.sideBarOpen })
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const profile =
|
||||
user && items.find((i) => i.user_created?.id === user.id && i.layer?.userProfileLayer)
|
||||
profile
|
||||
? setUserProfile(profile)
|
||||
: setUserProfile({ id: crypto.randomUUID(), name: user?.first_name ?? '', text: '' })
|
||||
}, [user, items])
|
||||
|
||||
const nameRef = useRef<HTMLHeadingElement>(null)
|
||||
const [nameWidth, setNameWidth] = useState<number>(0)
|
||||
|
||||
@ -40,128 +23,42 @@ export default function NavBar({ appName }: { appName: string }) {
|
||||
!appState.embedded && nameRef.current && setNameWidth(nameRef.current.scrollWidth)
|
||||
}, [nameRef, appName, appState.embedded])
|
||||
|
||||
const onLogout = async () => {
|
||||
await toast.promise(logout(), {
|
||||
success: {
|
||||
render() {
|
||||
return 'Bye bye'
|
||||
},
|
||||
// other options
|
||||
icon: '👋',
|
||||
},
|
||||
error: {
|
||||
render({ data }) {
|
||||
return JSON.stringify(data)
|
||||
},
|
||||
},
|
||||
pending: 'logging out ..',
|
||||
})
|
||||
}
|
||||
|
||||
if (!appState.embedded) {
|
||||
return (
|
||||
<>
|
||||
<div className='tw-navbar tw-bg-base-100 tw-z-[9998] tw-shadow-xl tw-relative'>
|
||||
<div className='tw:navbar tw:bg-base-100 tw:z-9998 tw:shadow-xl tw:relative tw:p-0'>
|
||||
<button
|
||||
className='tw-btn tw-btn-square tw-btn-ghost'
|
||||
className='tw:btn tw:btn-square tw:btn-ghost tw:ml-3'
|
||||
aria-controls='#sidenav'
|
||||
aria-haspopup='true'
|
||||
onClick={() => toggleSidebar()}
|
||||
>
|
||||
<Bars3Icon className='tw-inline-block tw-w-5 tw-h-5' />
|
||||
<Bars3Icon className='tw:inline-block tw:w-5 tw:h-5' />
|
||||
</button>
|
||||
<div className='tw-flex-1 tw-mr-2'>
|
||||
<div className='tw:flex-1 tw:mr-2'>
|
||||
<div
|
||||
className={'tw-flex-1 tw-truncate tw-grid tw-grid-flow-col'}
|
||||
className={'tw:flex-1 tw:truncate tw:grid tw:grid-flow-col'}
|
||||
style={{ maxWidth: nameWidth + 60 }}
|
||||
>
|
||||
<Link
|
||||
className='tw-btn tw-btn-ghost tw-px-2 tw-normal-case tw-text-xl tw-flex-1 tw-truncate'
|
||||
className='tw:btn tw:btn-ghost tw:px-2 tw:normal-case tw:text-xl tw:flex-1 tw:truncate'
|
||||
to={'/'}
|
||||
>
|
||||
<h1 ref={nameRef} className='tw-truncate'>
|
||||
<h1 ref={nameRef} className='tw:truncate'>
|
||||
{appName}
|
||||
</h1>
|
||||
</Link>
|
||||
<button
|
||||
className='tw-btn tw-px-2 tw-btn-ghost'
|
||||
className='tw:btn tw:px-2 tw:btn-ghost'
|
||||
onClick={() => window.my_modal_3.showModal()}
|
||||
>
|
||||
<QuestionMarkIcon className='tw-h-5 tw-w-5' />
|
||||
<QuestionMarkIcon className='tw:h-5 tw:w-5' />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isAuthenticated ? (
|
||||
<div className='tw-flex-none'>
|
||||
<Link
|
||||
to={`${userProfile.id && '/item/' + userProfile.id}`}
|
||||
className='tw-flex tw-items-center'
|
||||
>
|
||||
{userProfile.image && (
|
||||
<div className='tw-avatar'>
|
||||
<div className='tw-w-10 tw-rounded-full'>
|
||||
<img src={appState.assetsApi.url + userProfile.image} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className='tw-ml-2 tw-mr-2'>{userProfile.name || user?.first_name}</div>
|
||||
</Link>
|
||||
<div className='tw-dropdown tw-dropdown-end'>
|
||||
<label tabIndex={0} className='tw-btn tw-btn-ghost tw-btn-square'>
|
||||
<EllipsisVerticalIcon className='tw-h-5 tw-w-5' />
|
||||
</label>
|
||||
<ul
|
||||
tabIndex={0}
|
||||
className='tw-menu tw-menu-compact tw-dropdown-content tw-mt-3 tw-p-2 tw-shadow tw-bg-base-100 tw-rounded-box tw-w-52 !tw-z-[10000]'
|
||||
>
|
||||
<li>
|
||||
<Link to={`${userProfile.id && '/edit-item/' + userProfile.id}`}>Profile</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to={'/user-settings'}>Settings</Link>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
onClick={() => {
|
||||
void onLogout()
|
||||
}}
|
||||
>
|
||||
Logout
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<div className='tw-hidden md:tw-flex'>
|
||||
<Link to={'/login'}>
|
||||
<div className='tw-btn tw-btn-ghost tw-mr-2'>Login</div>
|
||||
</Link>
|
||||
|
||||
<Link to={'/signup'}>
|
||||
<div className='tw-btn tw-btn-ghost tw-mr-2'>Sign Up</div>
|
||||
</Link>
|
||||
</div>
|
||||
<div className='tw-dropdown tw-dropdown-end'>
|
||||
<label tabIndex={1} className='tw-btn tw-btn-ghost md:tw-hidden'>
|
||||
<EllipsisVerticalIcon className='tw-h-5 tw-w-5' />
|
||||
</label>
|
||||
<ul
|
||||
tabIndex={1}
|
||||
className='tw-menu tw-dropdown-content tw-mt-3 tw-p-2 tw-shadow tw-bg-base-100 tw-rounded-box tw-w-52 !tw-z-[10000]'
|
||||
>
|
||||
<li>
|
||||
<Link to={'/login'}>Login</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to={'/signup'}>Sign Up</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{appState.showThemeControl && <ThemeControl />}
|
||||
<UserControl />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
@ -34,19 +34,16 @@ export function SideBar({ routes, bottomRoutes }: { routes: Route[]; bottomRoute
|
||||
return (
|
||||
<nav
|
||||
id='sidenav'
|
||||
className={`${appState.sideBarOpen ? 'tw-translate-x-0' : '-tw-translate-x-full'}
|
||||
${appState.sideBarSlim ? 'tw-w-14' : 'tw-w-48'}
|
||||
${appState.embedded ? 'tw-mt-0 tw-h-[100dvh]' : 'tw-mt-16 tw-h-[calc(100dvh-64px)]'}
|
||||
tw-fixed tw-left-0 tw-transition-all tw-duration-300 tw-top-0 tw-z-[10035]
|
||||
tw-overflow-hidden tw-shadow-xl dark:tw-bg-zinc-800`}
|
||||
className={`${appState.sideBarOpen ? 'tw:translate-x-0' : 'tw:-translate-x-full'}
|
||||
${appState.sideBarSlim ? 'tw:w-14' : 'tw:w-48'}
|
||||
${appState.embedded ? 'tw:mt-5.5 tw:h-[calc(100dvh-22px)]' : 'tw:mt-16 tw:h-[calc(100dvh-64px)]'}
|
||||
tw:fixed tw:left-0 tw:transition-all tw:duration-300 tw:top-0 tw:z-10035
|
||||
tw:overflow-hidden tw:shadow-xl tw:dark:bg-zinc-800`}
|
||||
>
|
||||
<div
|
||||
className={`tw-flex tw-flex-col ${appState.embedded ? 'tw-h-full' : 'tw-h-[calc(100dvh-64px)]'}`}
|
||||
className={`tw:flex tw:flex-col ${appState.embedded ? 'tw:h-full' : 'tw:h-[calc(100dvh-64px)]'}`}
|
||||
>
|
||||
<ul
|
||||
className='tw-menu tw-w-full tw-bg-base-100 tw-text-base-content tw-p-0'
|
||||
data-te-sidenav-menu-ref
|
||||
>
|
||||
<ul className='tw:menu tw:w-full tw:bg-base-100 tw:text-base-content tw:p-0'>
|
||||
{routes.map((route, k) => {
|
||||
return (
|
||||
<li className='' key={k}>
|
||||
@ -59,7 +56,7 @@ export function SideBar({ routes, bottomRoutes }: { routes: Route[]; bottomRoute
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
to={`${route.path}${params && '?' + params.toString()}`}
|
||||
className={({ isActive }) =>
|
||||
`${isActive ? 'tw-font-semibold tw-bg-base-200 !tw-rounded-none' : 'tw-font-normal !tw-rounded-none'}`
|
||||
`${isActive ? 'tw:font-semibold tw:bg-base-200 tw:rounded-none!' : 'tw:font-normal tw:rounded-none!'}`
|
||||
}
|
||||
onClick={() => {
|
||||
if (screen.width < 640 && !appState.sideBarSlim) toggleSidebarOpen()
|
||||
@ -67,7 +64,7 @@ export function SideBar({ routes, bottomRoutes }: { routes: Route[]; bottomRoute
|
||||
>
|
||||
{route.icon}
|
||||
<span
|
||||
className={`${appState.sideBarSlim ? 'tw-hidden' : ''}`}
|
||||
className={`${appState.sideBarSlim ? 'tw:hidden' : ''}`}
|
||||
data-te-sidenav-slim='false'
|
||||
>
|
||||
{route.name}
|
||||
@ -75,7 +72,7 @@ export function SideBar({ routes, bottomRoutes }: { routes: Route[]; bottomRoute
|
||||
{(location.pathname.includes(route.path) && route.path.length > 1) ||
|
||||
location.pathname === route.path ? (
|
||||
<span
|
||||
className='tw-absolute tw-inset-y-0 tw-left-0 tw-w-1 tw-rounded-tr-md tw-rounded-br-md tw-bg-primary '
|
||||
className='tw:absolute tw:inset-y-0 tw:left-0 tw:w-1 tw:rounded-tr-md tw:rounded-br-md tw:bg-primary '
|
||||
aria-hidden='true'
|
||||
></span>
|
||||
) : null}
|
||||
@ -88,12 +85,12 @@ export function SideBar({ routes, bottomRoutes }: { routes: Route[]; bottomRoute
|
||||
|
||||
<div
|
||||
id='slim-toggler'
|
||||
className='tw-w-full tw-bg-base-100 tw-flex-1 tw-grid tw-place-items-end'
|
||||
className='tw:w-full tw:bg-base-100 tw:flex-1 tw:grid tw:place-items-end'
|
||||
aria-haspopup='true'
|
||||
>
|
||||
<div className='tw-w-full'>
|
||||
<div className='tw:w-full'>
|
||||
<ul
|
||||
className='tw-menu tw-w-full tw-bg-base-100 tw-text-base-content tw-p-0 tw-mb-0'
|
||||
className='tw:menu tw:w-full tw:bg-base-100 tw:text-base-content tw:p-0 tw:mb-0'
|
||||
data-te-sidenav-menu-ref
|
||||
>
|
||||
{bottomRoutes?.map((route, k) => {
|
||||
@ -107,7 +104,7 @@ export function SideBar({ routes, bottomRoutes }: { routes: Route[]; bottomRoute
|
||||
target={route.blank ? '_blank' : '_self'}
|
||||
to={route.path}
|
||||
className={({ isActive }) =>
|
||||
`${isActive ? 'tw-font-semibold tw-bg-base-200 !tw-rounded-none' : 'tw-font-normal !tw-rounded-none'}`
|
||||
`${isActive ? 'tw:font-semibold tw:bg-base-200 tw:rounded-none!' : 'tw:font-normal tw:rounded-none!'}`
|
||||
}
|
||||
onClick={() => {
|
||||
if (screen.width < 640 && !appState.sideBarSlim) toggleSidebarOpen()
|
||||
@ -115,7 +112,7 @@ export function SideBar({ routes, bottomRoutes }: { routes: Route[]; bottomRoute
|
||||
>
|
||||
{route.icon}
|
||||
<span
|
||||
className={`${appState.sideBarSlim ? 'tw-hidden' : ''}`}
|
||||
className={`${appState.sideBarSlim ? 'tw:hidden' : ''}`}
|
||||
data-te-sidenav-slim='false'
|
||||
>
|
||||
{route.name}
|
||||
@ -123,7 +120,7 @@ export function SideBar({ routes, bottomRoutes }: { routes: Route[]; bottomRoute
|
||||
{(location.pathname.includes(route.path) && route.path.length > 1) ||
|
||||
location.pathname === route.path ? (
|
||||
<span
|
||||
className='tw-absolute tw-inset-y-0 tw-left-0 tw-w-1 tw-rounded-tr-md tw-rounded-br-md tw-bg-primary '
|
||||
className='tw:absolute tw:inset-y-0 tw:left-0 tw:w-1 tw:rounded-tr-md tw:rounded-br-md tw:bg-primary '
|
||||
aria-hidden='true'
|
||||
></span>
|
||||
) : null}
|
||||
@ -136,8 +133,8 @@ export function SideBar({ routes, bottomRoutes }: { routes: Route[]; bottomRoute
|
||||
|
||||
<ChevronRightIcon
|
||||
className={
|
||||
'tw-w-5 tw-h-5 tw-mb-4 tw-mr-4 tw-cursor-pointer tw-float-right tw-delay-400 tw-duration-500 tw-transition-all ' +
|
||||
(!appState.sideBarSlim ? 'tw-rotate-180' : '')
|
||||
'tw:w-5 tw:h-5 tw:mb-4 tw:mr-5 tw:mt-2 tw:cursor-pointer tw:float-right tw:delay-400 tw:duration-500 tw:transition-all ' +
|
||||
(!appState.sideBarSlim ? 'tw:rotate-180' : '')
|
||||
}
|
||||
onClick={() => toggleSidebarSlim()}
|
||||
/>
|
||||
|
||||
119
src/Components/AppShell/UserControl.tsx
Normal file
119
src/Components/AppShell/UserControl.tsx
Normal file
@ -0,0 +1,119 @@
|
||||
import EllipsisVerticalIcon from '@heroicons/react/16/solid/EllipsisVerticalIcon'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import { useAuth } from '#components/Auth/useAuth'
|
||||
import { useItems } from '#components/Map/hooks/useItems'
|
||||
|
||||
import { useAppState } from './hooks/useAppState'
|
||||
|
||||
import type { Item } from '#types/Item'
|
||||
|
||||
export const UserControl = () => {
|
||||
const { isAuthenticated, user, logout } = useAuth()
|
||||
const appState = useAppState()
|
||||
|
||||
const [userProfile, setUserProfile] = useState<Item>({} as Item)
|
||||
const items = useItems()
|
||||
|
||||
useEffect(() => {
|
||||
const profile =
|
||||
user && items.find((i) => i.user_created?.id === user.id && i.layer?.userProfileLayer)
|
||||
profile
|
||||
? setUserProfile(profile)
|
||||
: setUserProfile({ id: crypto.randomUUID(), name: user?.first_name ?? '', text: '' })
|
||||
}, [user, items])
|
||||
|
||||
const onLogout = async () => {
|
||||
await toast.promise(logout(), {
|
||||
success: {
|
||||
render() {
|
||||
return 'Bye bye'
|
||||
},
|
||||
// other options
|
||||
icon: '👋',
|
||||
},
|
||||
error: {
|
||||
render({ data }) {
|
||||
return JSON.stringify(data)
|
||||
},
|
||||
},
|
||||
pending: 'logging out ..',
|
||||
})
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{isAuthenticated ? (
|
||||
<div className='tw:flex tw:mr-2'>
|
||||
<Link
|
||||
to={`${userProfile.id && '/item/' + userProfile.id}`}
|
||||
className='tw:flex tw:items-center'
|
||||
>
|
||||
{userProfile.image && (
|
||||
<div className='tw:avatar'>
|
||||
<div className='tw:w-10 tw:rounded-full'>
|
||||
<img src={appState.assetsApi.url + userProfile.image} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className='tw:ml-2 tw:mr-2'>{userProfile.name || user?.first_name}</div>
|
||||
</Link>
|
||||
<div className='tw:dropdown tw:dropdown-end'>
|
||||
<label tabIndex={0} className='tw:btn tw:btn-ghost tw:btn-square'>
|
||||
<EllipsisVerticalIcon className='tw:h-5 tw:w-5' />
|
||||
</label>
|
||||
<ul
|
||||
tabIndex={0}
|
||||
className='tw:menu tw:menu-compact tw:dropdown-content tw:mt-4 tw:p-2 tw:shadow tw:bg-base-100 tw:rounded-box tw:w-52 tw:z-10000!'
|
||||
>
|
||||
<li>
|
||||
<Link to={`${userProfile.id && '/edit-item/' + userProfile.id}`}>Profile</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to={'/user-settings'}>Settings</Link>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
onClick={() => {
|
||||
void onLogout()
|
||||
}}
|
||||
>
|
||||
Logout
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className='tw:mr-2 tw:flex tw:items-center'>
|
||||
<div className='tw:hidden tw:md:flex'>
|
||||
<Link to={'/login'}>
|
||||
<div className='tw:self-center tw:btn tw:btn-ghost tw:mr-2'>Login</div>
|
||||
</Link>
|
||||
|
||||
<Link to={'/signup'}>
|
||||
<div className='tw:btn tw:btn-ghost tw:mr-2'>Sign Up</div>
|
||||
</Link>
|
||||
</div>
|
||||
<div className='tw:dropdown tw:dropdown-end'>
|
||||
<label tabIndex={1} className='tw:btn tw:btn-ghost tw:md:hidden'>
|
||||
<EllipsisVerticalIcon className='tw:h-5 tw:w-5' />
|
||||
</label>
|
||||
<ul
|
||||
tabIndex={1}
|
||||
className='tw:menu tw:dropdown-content tw:mt-4 tw:p-2 tw:shadow tw:bg-base-100 tw:rounded-box tw:w-52 tw:z-10000!'
|
||||
>
|
||||
<li>
|
||||
<Link to={'/login'}>Login</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to={'/signup'}>Sign Up</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -8,6 +8,7 @@ interface AppState {
|
||||
assetsApi: AssetsApi
|
||||
sideBarOpen: boolean
|
||||
sideBarSlim: boolean
|
||||
showThemeControl: boolean
|
||||
embedded: boolean
|
||||
openCollectiveApiKey: string
|
||||
}
|
||||
@ -18,6 +19,7 @@ const initialAppState: AppState = {
|
||||
assetsApi: {} as AssetsApi,
|
||||
sideBarOpen: false,
|
||||
sideBarSlim: false,
|
||||
showThemeControl: false,
|
||||
embedded: false,
|
||||
openCollectiveApiKey: '',
|
||||
}
|
||||
|
||||
12
src/Components/AppShell/hooks/useTheme.tsx
Normal file
12
src/Components/AppShell/hooks/useTheme.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { useEffect } from 'react'
|
||||
|
||||
export const useTheme = (defaultTheme = 'default') => {
|
||||
useEffect(() => {
|
||||
const savedTheme = localStorage.getItem('theme')
|
||||
const initialTheme = savedTheme ? (JSON.parse(savedTheme) as string) : defaultTheme
|
||||
if (initialTheme !== 'default') {
|
||||
document.documentElement.setAttribute('data-theme', defaultTheme)
|
||||
localStorage.setItem('theme', JSON.stringify(initialTheme))
|
||||
}
|
||||
}, [defaultTheme])
|
||||
}
|
||||
@ -53,39 +53,39 @@ export function LoginPage() {
|
||||
}, [onLogin])
|
||||
|
||||
return (
|
||||
<MapOverlayPage backdrop className='tw-max-w-xs tw-h-fit'>
|
||||
<h2 className='tw-text-2xl tw-font-semibold tw-mb-2 tw-text-center'>Login</h2>
|
||||
<MapOverlayPage backdrop className='tw:max-w-xs tw:h-fit'>
|
||||
<h2 className='tw:text-2xl tw:font-semibold tw:mb-2 tw:text-center'>Login</h2>
|
||||
<input
|
||||
type='email'
|
||||
placeholder='E-Mail'
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className='tw-input tw-input-bordered tw-w-full tw-max-w-xs'
|
||||
className='tw:input tw:input-bordered tw:w-full tw:max-w-xs'
|
||||
/>
|
||||
<input
|
||||
type='password'
|
||||
placeholder='Password'
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className='tw-input tw-input-bordered tw-w-full tw-max-w-xs'
|
||||
className='tw:input tw:input-bordered tw:w-full tw:max-w-xs'
|
||||
/>
|
||||
<div className='tw-text-right tw-text-primary'>
|
||||
<div className='tw:text-right tw:text-primary'>
|
||||
<Link to='/reset-password'>
|
||||
<span className='tw-text-sm tw-inline-block hover:tw-text-primary hover:tw-underline hover:tw-cursor-pointer tw-transition tw-duration-200'>
|
||||
<span className='tw:text-sm tw:inline-block tw:hover:text-primary tw:hover:underline tw:hover:cursor-pointer tw:transition tw:duration-200'>
|
||||
Forgot Password?
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
<div className='tw-card-actions'>
|
||||
<div className='tw:card-actions'>
|
||||
<button
|
||||
className={
|
||||
loading
|
||||
? 'tw-btn tw-btn-disabled tw-btn-block tw-btn-primary'
|
||||
: 'tw-btn tw-btn-primary tw-btn-block'
|
||||
? 'tw:btn tw:btn-disabled tw:btn-block tw:btn-primary'
|
||||
: 'tw:btn tw:btn-primary tw:btn-block'
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
onClick={() => onLogin()}
|
||||
>
|
||||
{loading ? <span className='tw-loading tw-loading-spinner'></span> : 'Login'}
|
||||
{loading ? <span className='tw:loading tw:loading-spinner'></span> : 'Login'}
|
||||
</button>
|
||||
</div>
|
||||
</MapOverlayPage>
|
||||
|
||||
@ -36,26 +36,26 @@ export function RequestPasswordPage({ resetUrl }: { resetUrl: string }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<MapOverlayPage backdrop className='tw-max-w-xs tw-h-fit'>
|
||||
<h2 className='tw-text-2xl tw-font-semibold tw-mb-2 tw-text-center'>Reset Password</h2>
|
||||
<MapOverlayPage backdrop className='tw:max-w-xs tw:h-fit'>
|
||||
<h2 className='tw:text-2xl tw:font-semibold tw:mb-2 tw:text-center'>Reset Password</h2>
|
||||
<input
|
||||
type='email'
|
||||
placeholder='E-Mail'
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className='tw-input tw-input-bordered tw-w-full tw-max-w-xs'
|
||||
className='tw:input tw:input-bordered tw:w-full tw:max-w-xs'
|
||||
/>
|
||||
<div className='tw-card-actions tw-mt-4'>
|
||||
<div className='tw:card-actions tw:mt-4'>
|
||||
<button
|
||||
className={
|
||||
loading
|
||||
? 'tw-btn tw-btn-disabled tw-btn-block tw-btn-primary'
|
||||
: 'tw-btn tw-btn-primary tw-btn-block'
|
||||
? 'tw:btn tw:btn-disabled tw:btn-block tw:btn-primary'
|
||||
: 'tw:btn tw:btn-primary tw:btn-block'
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
onClick={() => onReset()}
|
||||
>
|
||||
{loading ? <span className='tw-loading tw-loading-spinner'></span> : 'Send'}
|
||||
{loading ? <span className='tw:loading tw:loading-spinner'></span> : 'Send'}
|
||||
</button>
|
||||
</div>
|
||||
</MapOverlayPage>
|
||||
|
||||
@ -36,25 +36,25 @@ export function SetNewPasswordPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<MapOverlayPage backdrop className='tw-max-w-xs tw-h-fit'>
|
||||
<h2 className='tw-text-2xl tw-font-semibold tw-mb-2 tw-text-center'>Set new Password</h2>
|
||||
<MapOverlayPage backdrop className='tw:max-w-xs tw:h-fit'>
|
||||
<h2 className='tw:text-2xl tw:font-semibold tw:mb-2 tw:text-center'>Set new Password</h2>
|
||||
<input
|
||||
type='password'
|
||||
placeholder='Password'
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className='tw-input tw-input-bordered tw-w-full tw-max-w-xs'
|
||||
className='tw:input tw:input-bordered tw:w-full tw:max-w-xs'
|
||||
/>
|
||||
<div className='tw-card-actions tw-mt-4'>
|
||||
<div className='tw:card-actions tw:mt-4'>
|
||||
<button
|
||||
className={
|
||||
loading
|
||||
? 'tw-btn tw-btn-disabled tw-btn-block tw-btn-primary'
|
||||
: 'tw-btn tw-btn-primary tw-btn-block'
|
||||
? 'tw:btn tw:btn-disabled tw:btn-block tw:btn-primary'
|
||||
: 'tw:btn tw:btn-primary tw:btn-block'
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
onClick={() => onReset()}
|
||||
>
|
||||
{loading ? <span className='tw-loading tw-loading-spinner'></span> : 'Set'}
|
||||
{loading ? <span className='tw:loading tw:loading-spinner'></span> : 'Set'}
|
||||
</button>
|
||||
</div>
|
||||
</MapOverlayPage>
|
||||
|
||||
@ -55,39 +55,39 @@ export function SignupPage() {
|
||||
}, [onRegister])
|
||||
|
||||
return (
|
||||
<MapOverlayPage backdrop className='tw-max-w-xs tw-h-fit'>
|
||||
<h2 className='tw-text-2xl tw-font-semibold tw-mb-2 tw-text-center'>Sign Up</h2>
|
||||
<MapOverlayPage backdrop className='tw:max-w-xs tw:h-fit'>
|
||||
<h2 className='tw:text-2xl tw:font-semibold tw:mb-2 tw:text-center'>Sign Up</h2>
|
||||
<input
|
||||
type='text'
|
||||
placeholder='Name'
|
||||
value={userName}
|
||||
onChange={(e) => setUserName(e.target.value)}
|
||||
className='tw-input tw-input-bordered tw-w-full tw-max-w-xs'
|
||||
className='tw:input tw:input-bordered tw:w-full tw:max-w-xs'
|
||||
/>
|
||||
<input
|
||||
type='email'
|
||||
placeholder='E-Mail'
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className='tw-input tw-input-bordered tw-w-full tw-max-w-xs'
|
||||
className='tw:input tw:input-bordered tw:w-full tw:max-w-xs'
|
||||
/>
|
||||
<input
|
||||
type='password'
|
||||
placeholder='Password'
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className='tw-input tw-input-bordered tw-w-full tw-max-w-xs'
|
||||
className='tw:input tw:input-bordered tw:w-full tw:max-w-xs'
|
||||
/>
|
||||
<div className='tw-card-actions tw-mt-4'>
|
||||
<div className='tw:card-actions tw:mt-4'>
|
||||
<button
|
||||
className={
|
||||
loading
|
||||
? 'tw-btn tw-btn-disabled tw-btn-block tw-btn-primary'
|
||||
: 'tw-btn tw-btn-primary tw-btn-block'
|
||||
? 'tw:btn tw:btn-disabled tw:btn-block tw:btn-primary'
|
||||
: 'tw:btn tw:btn-primary tw:btn-block'
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
onClick={() => onRegister()}
|
||||
>
|
||||
{loading ? <span className='tw-loading tw-loading-spinner'></span> : 'Sign Up'}
|
||||
{loading ? <span className='tw:loading tw:loading-spinner'></span> : 'Sign Up'}
|
||||
</button>
|
||||
</div>
|
||||
</MapOverlayPage>
|
||||
|
||||
@ -20,14 +20,14 @@ export function Modal({
|
||||
return (
|
||||
<>
|
||||
{/* You can open the modal using ID.showModal() method */}
|
||||
<dialog id='my_modal_3' className='tw-modal tw-transition-all tw-duration-300'>
|
||||
<form method='dialog' className='tw-modal-box tw-transition-none'>
|
||||
<button className='tw-btn tw-btn-sm tw-btn-circle tw-btn-ghost tw-absolute tw-right-2 tw-top-2 focus:tw-outline-none'>
|
||||
<dialog id='my_modal_3' className='tw:modal tw:transition-all tw:duration-300'>
|
||||
<form method='dialog' className='tw:modal-box tw:transition-none'>
|
||||
<button className='tw:btn tw:btn-sm tw:btn-circle tw:btn-ghost tw:absolute tw:right-2 tw:top-2 tw:focus:outline-hidden'>
|
||||
✕
|
||||
</button>
|
||||
{children}
|
||||
</form>
|
||||
<form method='dialog' className='tw-modal-backdrop'>
|
||||
<form method='dialog' className='tw:modal-backdrop'>
|
||||
<button>close</button>
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
@ -39,56 +39,56 @@ export function Quests() {
|
||||
return (
|
||||
<>
|
||||
{questsOpen ? (
|
||||
<div className='tw-card tw-w-48 tw-bg-base-100 tw-shadow-xl tw-absolute tw-bottom-4 tw-left-4 tw-z-[2000]'>
|
||||
<div className='tw-card-body tw-p-4 tw-pt-0'>
|
||||
<div className='tw-card-actions tw-justify-end'>
|
||||
<div className='tw:card tw:w-48 tw:bg-base-100 tw:shadow-xl tw:absolute tw:bottom-4 tw:left-4 tw:z-2000'>
|
||||
<div className='tw:card-body tw:p-4 tw:pt-0'>
|
||||
<div className='tw:card-actions tw:justify-end'>
|
||||
<label
|
||||
className='tw-btn tw-btn-sm tw-btn-circle tw-btn-ghost tw-absolute tw-right-1 tw-top-1'
|
||||
className='tw:btn tw:btn-sm tw:btn-circle tw:btn-ghost tw:absolute tw:right-1 tw:top-1'
|
||||
onClick={() => setQuestsOpen(false)}
|
||||
>
|
||||
✕
|
||||
</label>
|
||||
</div>
|
||||
<h2 className='tw-card-title tw-m-auto '>
|
||||
<h2 className='tw:card-title tw:m-auto '>
|
||||
Level 1
|
||||
<QuestionMarkCircleIcon />
|
||||
</h2>
|
||||
<ul className='tw-flex-row'>
|
||||
<ul className='tw:flex-row'>
|
||||
<li>
|
||||
<label className='tw-label tw-justify-normal tw-pt-1 tw-pb-0'>
|
||||
<label className='tw:label tw:justify-normal tw:pt-1 tw:pb-0'>
|
||||
<input
|
||||
type='checkbox'
|
||||
readOnly={true}
|
||||
className='tw-checkbox tw-checkbox-xs tw-checkbox-success'
|
||||
className='tw:checkbox tw:checkbox-xs tw:checkbox-success'
|
||||
checked={isAuthenticated || false}
|
||||
/>
|
||||
<span className='tw-text-sm tw-label-text tw-mx-2'>Sign Up</span>
|
||||
<span className='tw:text-sm tw:label-text tw:mx-2'>Sign Up</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label className='tw-label tw-justify-normal tw-pt-1 tw-pb-0'>
|
||||
<label className='tw:label tw:justify-normal tw:pt-1 tw:pb-0'>
|
||||
<input
|
||||
type='checkbox'
|
||||
readOnly={true}
|
||||
className='tw-checkbox tw-checkbox-xs tw-checkbox-success'
|
||||
className='tw:checkbox tw:checkbox-xs tw:checkbox-success'
|
||||
checked={!!profile?.text}
|
||||
/>
|
||||
<span className='tw-text-sm tw-label-text tw-mx-2'>Fill Profile</span>
|
||||
<span className='tw:text-sm tw:label-text tw:mx-2'>Fill Profile</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label className='tw-label tw-justify-normal tw-pt-1 tw-pb-0'>
|
||||
<label className='tw:label tw:justify-normal tw:pt-1 tw:pb-0'>
|
||||
<input
|
||||
type='checkbox'
|
||||
readOnly={true}
|
||||
className='tw-checkbox tw-checkbox-xs tw-checkbox-success'
|
||||
className='tw:checkbox tw:checkbox-xs tw:checkbox-success'
|
||||
checked={!!profile?.image}
|
||||
/>
|
||||
<span className='tw-text-sm tw-label-text tw-mx-2'>Upload Avatar</span>
|
||||
<span className='tw:text-sm tw:label-text tw:mx-2'>Upload Avatar</span>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
{/** <button className='tw-btn tw-btn-xs tw-btn-neutral tw-w-fit tw-self-center tw-mt-1'>Next ></button> */}{' '}
|
||||
{/** <button className='tw:btn tw:btn-xs tw:btn-neutral tw:w-fit tw:self-center tw:mt-1'>Next ></button> */}{' '}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
|
||||
@ -91,9 +91,10 @@ export const Autocomplete = ({
|
||||
onChange={(e) => handleChange(e)}
|
||||
tabIndex='-1'
|
||||
onKeyDown={handleKeyDown}
|
||||
className='tw:border-none tw:focus:outline-none tw:focus:ring-0 tw:mt-5'
|
||||
/>
|
||||
<ul
|
||||
className={`tw-absolute tw-z-[4000] ${filteredSuggestions.length > 0 && 'tw-bg-base-100 tw-rounded-xl tw-p-2'}`}
|
||||
className={`tw:absolute tw:z-4000 ${filteredSuggestions.length > 0 && 'tw:bg-base-100 tw:rounded-xl tw:p-2'}`}
|
||||
>
|
||||
{filteredSuggestions.map((suggestion, index) => (
|
||||
<li key={index} onClick={() => handleSuggestionClick(suggestion)}>
|
||||
|
||||
@ -14,7 +14,7 @@ const ComboBoxInput = ({ id, options, value, onValueChange }: ComboBoxProps) =>
|
||||
return (
|
||||
<select
|
||||
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'
|
||||
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 tw:focus:outline-hidden tw:focus:ring-indigo-500 tw:focus:border-indigo-500 tw:sm:text-sm'
|
||||
onChange={handleChange}
|
||||
defaultValue={value}
|
||||
>
|
||||
|
||||
@ -42,10 +42,10 @@ export function TextAreaInput({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`tw-form-control tw-w-full ${containerStyle ?? ''}`}>
|
||||
<div className={`tw:form-control tw:w-full ${containerStyle ?? ''}`}>
|
||||
{labelTitle ? (
|
||||
<label className='tw-label'>
|
||||
<span className={`tw-label-text tw-text-base-content ${labelStyle ?? ''}`}>
|
||||
<label className='tw:label'>
|
||||
<span className={`tw:label-text tw:text-base-content ${labelStyle ?? ''}`}>
|
||||
{labelTitle}
|
||||
</span>
|
||||
</label>
|
||||
@ -55,7 +55,7 @@ export function TextAreaInput({
|
||||
ref={ref}
|
||||
value={inputValue}
|
||||
name={dataField}
|
||||
className={`tw-textarea tw-textarea-bordered tw-w-full tw-leading-5 ${inputStyle ?? ''}`}
|
||||
className={`tw:textarea tw:textarea-bordered tw:w-full tw:leading-5 ${inputStyle ?? ''}`}
|
||||
placeholder={placeholder ?? ''}
|
||||
onChange={handleChange}
|
||||
></textarea>
|
||||
|
||||
@ -9,9 +9,9 @@ describe('<TextInput />', () => {
|
||||
cy.get('input').should('have.attr', 'type', 'text')
|
||||
cy.get('input').should('have.attr', 'placeholder', '')
|
||||
cy.get('input').should('have.attr', 'required')
|
||||
cy.get('input').should('have.class', 'tw-input')
|
||||
cy.get('input').should('have.class', 'tw-input-bordered')
|
||||
cy.get('input').should('have.class', 'tw-w-full')
|
||||
cy.get('input').should('have.class', 'input')
|
||||
cy.get('input').should('have.class', 'input-bordered')
|
||||
cy.get('input').should('have.class', 'tw:w-full')
|
||||
})
|
||||
|
||||
it('renders with given labelTitle', () => {
|
||||
|
||||
@ -47,10 +47,10 @@ export function TextInput({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`tw-form-control ${containerStyle ?? ''}`}>
|
||||
<div className={`tw:form-control ${containerStyle ?? ''}`}>
|
||||
{labelTitle ? (
|
||||
<label className='tw-label'>
|
||||
<span className={`tw-label-text tw-text-base-content ${labelStyle ?? ''}`}>
|
||||
<label className='tw:label'>
|
||||
<span className={`tw:label-text tw:text-base-content ${labelStyle ?? ''}`}>
|
||||
{labelTitle}
|
||||
</span>
|
||||
</label>
|
||||
@ -64,7 +64,7 @@ export function TextInput({
|
||||
placeholder={placeholder ?? ''}
|
||||
autoComplete={autocomplete}
|
||||
onChange={handleChange}
|
||||
className={`tw-input tw-input-bordered tw-w-full ${inputStyle ?? ''}`}
|
||||
className={`tw:input tw:input-bordered tw:w-full ${inputStyle ?? ''}`}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
exports[`<ComboBoxInput /> > renders properly 1`] = `
|
||||
<select
|
||||
class="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"
|
||||
class="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 tw:focus:outline-hidden tw:focus:ring-indigo-500 tw:focus:border-indigo-500 tw:sm:text-sm"
|
||||
>
|
||||
<option
|
||||
value="Option 1"
|
||||
|
||||
@ -2,19 +2,19 @@
|
||||
|
||||
exports[`<TextAreaInput /> > labelTitle > sets label 1`] = `
|
||||
<div
|
||||
class="tw-form-control tw-w-full "
|
||||
class="tw:form-control tw:w-full "
|
||||
>
|
||||
<label
|
||||
class="tw-label"
|
||||
class="tw:label"
|
||||
>
|
||||
<span
|
||||
class="tw-label-text tw-text-base-content "
|
||||
class="tw:label-text tw:text-base-content "
|
||||
>
|
||||
My Title
|
||||
</span>
|
||||
</label>
|
||||
<textarea
|
||||
class="tw-textarea tw-textarea-bordered tw-w-full tw-leading-5 "
|
||||
class="tw:textarea tw:textarea-bordered tw:w-full tw:leading-5 "
|
||||
placeholder=""
|
||||
required=""
|
||||
/>
|
||||
@ -23,10 +23,10 @@ exports[`<TextAreaInput /> > labelTitle > sets label 1`] = `
|
||||
|
||||
exports[`<TextAreaInput /> > renders properly 1`] = `
|
||||
<div
|
||||
class="tw-form-control tw-w-full "
|
||||
class="tw:form-control tw:w-full "
|
||||
>
|
||||
<textarea
|
||||
class="tw-textarea tw-textarea-bordered tw-w-full tw-leading-5 "
|
||||
class="tw:textarea tw:textarea-bordered tw:w-full tw:leading-5 "
|
||||
placeholder=""
|
||||
required=""
|
||||
/>
|
||||
|
||||
@ -2,19 +2,19 @@
|
||||
|
||||
exports[`<TextInput /> > labelTitle > sets label 1`] = `
|
||||
<div
|
||||
class="tw-form-control "
|
||||
class="tw:form-control "
|
||||
>
|
||||
<label
|
||||
class="tw-label"
|
||||
class="tw:label"
|
||||
>
|
||||
<span
|
||||
class="tw-label-text tw-text-base-content "
|
||||
class="tw:label-text tw:text-base-content "
|
||||
>
|
||||
My Title
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
class="tw-input tw-input-bordered tw-w-full "
|
||||
class="tw:input tw:input-bordered tw:w-full "
|
||||
placeholder=""
|
||||
required=""
|
||||
type="text"
|
||||
@ -25,10 +25,10 @@ exports[`<TextInput /> > labelTitle > sets label 1`] = `
|
||||
|
||||
exports[`<TextInput /> > renders properly 1`] = `
|
||||
<div
|
||||
class="tw-form-control "
|
||||
class="tw:form-control "
|
||||
>
|
||||
<input
|
||||
class="tw-input tw-input-bordered tw-w-full "
|
||||
class="tw:input tw:input-bordered tw:w-full "
|
||||
placeholder=""
|
||||
required=""
|
||||
type="text"
|
||||
|
||||
@ -31,11 +31,14 @@ export default function AddButton({
|
||||
return (
|
||||
<>
|
||||
{canAddItems() ? (
|
||||
<div className='tw-dropdown tw-dropdown-top tw-dropdown-end tw-dropdown-hover tw-z-500 tw-absolute tw-right-4 tw-bottom-4'>
|
||||
<label tabIndex={0} className='tw-z-500 tw-btn tw-btn-circle tw-shadow tw-bg-base-100'>
|
||||
<SVG src={PlusSVG} className='tw-h-5 tw-w-5' />
|
||||
<div className='tw:dropdown tw:dropdown-top tw:dropdown-end tw:dropdown-hover tw:z-500 tw:absolute tw:right-4 tw:bottom-4'>
|
||||
<label
|
||||
tabIndex={0}
|
||||
className='tw:z-500 tw:btn tw:btn-circle tw:btn-lg tw:shadow tw:bg-base-100'
|
||||
>
|
||||
<SVG src={PlusSVG} className='tw:h-5 tw:w-5' />
|
||||
</label>
|
||||
<ul tabIndex={0} className='tw-dropdown-content tw-pr-1 tw-list-none'>
|
||||
<ul tabIndex={0} className='tw:dropdown-content tw:pr-1 tw:list-none'>
|
||||
{layers.map(
|
||||
(layer) =>
|
||||
layer.api?.createItem &&
|
||||
@ -43,10 +46,10 @@ export default function AddButton({
|
||||
layer.listed && (
|
||||
<li key={layer.name}>
|
||||
<a>
|
||||
<div className='tw-tooltip tw-tooltip-left' data-tip={layer.menuText}>
|
||||
<div className='tw:tooltip tw:tooltip-left' data-tip={layer.menuText}>
|
||||
<button
|
||||
tabIndex={0}
|
||||
className='tw-z-500 tw-border-0 tw-pl-2 tw-p-0 tw-mb-3 tw-w-10 tw-h-10 tw-cursor-pointer tw-rounded-full tw-mouse tw-drop-shadow-md tw-transition tw-ease-in tw-duration-200 focus:tw-outline-none'
|
||||
className='tw:z-500 tw:border-0 tw:pl-2 tw:p-0 tw:mb-3 tw:w-10 tw:h-10 tw:cursor-pointer tw:rounded-full tw:mouse tw:drop-shadow-md tw:transition tw:ease-in tw:duration-200 tw:focus:outline-hidden'
|
||||
style={{ backgroundColor: layer.menuColor || '#777' }}
|
||||
onClick={() => {
|
||||
triggerAction(layer)
|
||||
@ -58,7 +61,7 @@ export default function AddButton({
|
||||
>
|
||||
<img
|
||||
src={layer.menuIcon}
|
||||
className='tw-h-6 tw-w-6 tw-text-white'
|
||||
className='tw:h-6 tw:w-6 tw:text-white'
|
||||
style={{ filter: 'invert(100%) brightness(200%)' }}
|
||||
/>
|
||||
</button>
|
||||
|
||||
@ -26,7 +26,7 @@ export const Control = ({
|
||||
<div
|
||||
ref={controlContainerRef}
|
||||
style={{ zIndex }}
|
||||
className={`${absolute && 'tw-absolute'} tw-z-[999] tw-flex-col ${position === 'topLeft' && 'tw-top-4 tw-left-4'} ${position === 'bottomLeft' && 'tw-bottom-4 tw-left-4'} ${position === 'topRight' && 'tw-bottom-4 tw-right-4'} ${position === 'bottomRight' && 'tw-bottom-4 tw-right-4'}`}
|
||||
className={`${absolute && 'tw:absolute'} tw:z-999 tw:flex-col ${position === 'topLeft' && 'tw:top-4 tw:left-4'} ${position === 'bottomLeft' && 'tw:bottom-4 tw:left-4'} ${position === 'topRight' && 'tw:bottom-4 tw:right-4'} ${position === 'bottomRight' && 'tw:bottom-4 tw:right-4'}`}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@ -28,32 +28,32 @@ export function FilterControl() {
|
||||
const visibleGroupTypes = useVisibleGroupType()
|
||||
|
||||
return (
|
||||
<div className='tw-card tw-bg-base-100 tw-shadow-xl tw-mt-2 tw-w-fit'>
|
||||
<div className='tw:card tw:bg-base-100 tw:shadow-xl tw:mt-2 tw:w-fit'>
|
||||
{open ? (
|
||||
<div className='tw-card-body tw-pr-4 tw-min-w-[8rem] tw-p-2 tw-w-fit tw-transition-all tw-duration-300'>
|
||||
<div className='tw:card-body tw:pr-4 tw:min-w-[8rem] tw:p-2 tw:w-fit tw:transition-all tw:duration-300'>
|
||||
<label
|
||||
className='tw-btn tw-btn-sm tw-rounded-2xl tw-btn-circle tw-btn-ghost hover:tw-bg-transparent tw-absolute tw-right-0 tw-top-0 tw-text-gray-600'
|
||||
className='tw:btn tw:btn-sm tw:rounded-2xl tw:btn-circle tw:btn-ghost tw:hover:bg-transparent tw:absolute tw:right-0 tw:top-0 tw:text-gray-600'
|
||||
onClick={() => {
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<p className='tw-text-center '>✕</p>
|
||||
<p className='tw:text-center '>✕</p>
|
||||
</label>
|
||||
<ul className='tw-flex-row'>
|
||||
<ul className='tw:flex-row'>
|
||||
{groupTypes.map((groupType) => (
|
||||
<li key={groupType.value}>
|
||||
<label
|
||||
htmlFor={groupType.value}
|
||||
className='tw-label tw-justify-normal tw-pt-1 tw-pb-1'
|
||||
className='tw:label tw:justify-normal tw:pt-1 tw:pb-1'
|
||||
>
|
||||
<input
|
||||
id={groupType.value}
|
||||
onChange={() => toggleVisibleGroupType(groupType.value)}
|
||||
type='checkbox'
|
||||
className='tw-checkbox tw-checkbox-xs tw-checkbox-success'
|
||||
className='tw:checkbox tw:checkbox-xs tw:checkbox-success'
|
||||
checked={isGroupTypeVisible(groupType.value)}
|
||||
/>
|
||||
<span className='tw-text-sm tw-label-text tw-mx-2 tw-cursor-pointer'>
|
||||
<span className='tw:text-sm tw:label-text tw:mx-2 tw:cursor-pointer'>
|
||||
{groupType.text}
|
||||
</span>
|
||||
</label>
|
||||
@ -62,17 +62,17 @@ export function FilterControl() {
|
||||
</ul>
|
||||
</div>
|
||||
) : (
|
||||
<div className='tw-indicator'>
|
||||
<div className='tw:indicator'>
|
||||
{visibleGroupTypes.length < groupTypes.length && (
|
||||
<span className='tw-indicator-item tw-badge tw-badge-success tw-h-4 tw-p-2 tw-translate-x-1/3 -tw-translate-y-1/3 tw-border-0'></span>
|
||||
<span className='tw:indicator-item tw:badge tw:badge-success tw:h-4 tw:p-2 tw:translate-x-1/3 tw:-translate-y-1/3 tw:border-0'></span>
|
||||
)}
|
||||
<div
|
||||
className='tw-card-body hover:tw-bg-slate-300 tw-card tw-p-2 tw-h-10 tw-w-10 tw-transition-all tw-duration-300 hover:tw-cursor-pointer'
|
||||
className='tw:card-body tw:hover:bg-slate-300 tw:card tw:p-2 tw:h-10 tw:w-10 tw:transition-all tw:duration-300 tw:hover:cursor-pointer'
|
||||
onClick={() => {
|
||||
setOpen(true)
|
||||
}}
|
||||
>
|
||||
<FunnelIcon className='size-6 tw-stroke-[2.5]' />
|
||||
<FunnelIcon className='size-6 tw:stroke-[2.5]' />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -9,15 +9,15 @@ export const GratitudeControl = () => {
|
||||
|
||||
if (isAuthenticated) {
|
||||
return (
|
||||
<div className='tw-card tw-bg-base-100 tw-shadow-xl tw-mt-2 tw-w-fit'>
|
||||
<div className='tw:card tw:bg-base-100 tw:shadow-xl tw:mt-2 tw:w-fit'>
|
||||
{
|
||||
<div
|
||||
className='tw-card-body hover:tw-bg-slate-300 tw-card tw-p-2 tw-h-10 tw-w-10 tw-transition-all tw-duration-300 hover:tw-cursor-pointer'
|
||||
className='tw:card-body tw:hover:bg-slate-300 tw:card tw:p-2 tw:h-10 tw:w-10 tw:transition-all tw:duration-300 tw:hover:cursor-pointer'
|
||||
onClick={() => {
|
||||
navigate('/select-user')
|
||||
}}
|
||||
>
|
||||
<HeartIcon className='tw-stroke-[2.5]' />
|
||||
<HeartIcon className='tw:stroke-[2.5]' />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -14,34 +14,34 @@ export function LayerControl() {
|
||||
const toggleVisibleLayer = useToggleVisibleLayer()
|
||||
|
||||
return (
|
||||
<div className='tw-card tw-bg-base-100 tw-shadow-xl tw-mt-2 tw-w-fit'>
|
||||
<div className='tw:card tw:bg-base-100 tw:shadow-xl tw:mt-2 tw:w-fit'>
|
||||
{open ? (
|
||||
<div className='tw-card-body tw-pr-4 tw-min-w-[8rem] tw-p-2 tw-transition-all tw-w-fit tw-duration-300'>
|
||||
<div className='tw:card-body tw:pr-4 tw:min-w-[8rem] tw:p-2 tw:transition-all tw:w-fit tw:duration-300'>
|
||||
<label
|
||||
className='tw-btn tw-btn-sm tw-rounded-2xl tw-btn-circle tw-btn-ghost hover:tw-bg-transparent tw-absolute tw-right-0 tw-top-0 tw-text-gray-600'
|
||||
className='tw:btn tw:btn-sm tw:rounded-2xl tw:btn-circle tw:btn-ghost tw:hover:bg-transparent tw:absolute tw:right-0 tw:top-0 tw:text-gray-600'
|
||||
onClick={() => {
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<p className='tw-text-center '>✕</p>
|
||||
<p className='tw:text-center '>✕</p>
|
||||
</label>
|
||||
<ul className='tw-flex-row'>
|
||||
<ul className='tw:flex-row'>
|
||||
{layers.map(
|
||||
(layer) =>
|
||||
layer.listed && (
|
||||
<li key={layer.name}>
|
||||
<label
|
||||
htmlFor={layer.name}
|
||||
className='tw-label tw-justify-normal tw-pt-1 tw-pb-1'
|
||||
className='tw:label tw:justify-normal tw:pt-1 tw:pb-1 tw:text-base-content'
|
||||
>
|
||||
<input
|
||||
id={layer.name}
|
||||
onChange={() => toggleVisibleLayer(layer)}
|
||||
type='checkbox'
|
||||
className='tw-checkbox tw-checkbox-xs tw-checkbox-success'
|
||||
className='tw:checkbox tw:checkbox-xs tw:checkbox-success'
|
||||
checked={isLayerVisible(layer)}
|
||||
/>
|
||||
<span className='tw-text-sm tw-label-text tw-mx-2 tw-cursor-pointer'>
|
||||
<span className='tw:text-sm tw:label-text tw:mx-2 tw:cursor-pointer'>
|
||||
{layer.name}
|
||||
</span>
|
||||
</label>
|
||||
@ -52,7 +52,7 @@ export function LayerControl() {
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className='tw-card-body hover:tw-bg-slate-300 tw-card tw-p-2 tw-h-10 tw-w-10 tw-transition-all tw-duration-300 hover:tw-cursor-pointer'
|
||||
className='tw:card-body tw:hover:bg-slate-300 tw:card tw:p-2 tw:h-10 tw:w-10 tw:transition-all tw:duration-300 tw:hover:cursor-pointer'
|
||||
onClick={() => {
|
||||
setOpen(true)
|
||||
}}
|
||||
|
||||
@ -43,9 +43,9 @@ export const LocateControl = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='tw-card tw-h-12 tw-w-12 tw-bg-base-100 tw-shadow-xl tw-items-center tw-justify-center hover:tw-bg-slate-300 hover:tw-cursor-pointer tw-transition-all tw-duration-300 tw-ml-2'>
|
||||
<div className='tw:card tw:flex-none tw:h-12 tw:w-12 tw:bg-base-100 tw:shadow-xl tw:items-center tw:justify-center tw:hover:bg-slate-300 tw:hover:cursor-pointer tw:transition-all tw:duration-300 tw:ml-2'>
|
||||
<div
|
||||
className='tw-card-body tw-card tw-p-2 tw-h-10 tw-w-10 '
|
||||
className='tw:card-body tw:card tw:p-2 tw:h-10 tw:w-10 '
|
||||
onClick={() => {
|
||||
if (active) {
|
||||
lc.stop()
|
||||
@ -57,11 +57,11 @@ export const LocateControl = () => {
|
||||
}}
|
||||
>
|
||||
{loading ? (
|
||||
<span className='tw-loading tw-loading-spinner tw-loading-md tw-mt-1'></span>
|
||||
<span className='tw:loading tw:loading-spinner tw:loading-md tw:mt-1'></span>
|
||||
) : (
|
||||
<SVG
|
||||
src={TargetSVG}
|
||||
className='tw-mt-1 tw-p-[1px]'
|
||||
className='tw:mt-1 tw:p-[1px]'
|
||||
style={{ fill: `${active ? '#fc8702' : 'currentColor'}` }}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -11,14 +11,14 @@ export function QuestControl() {
|
||||
''
|
||||
) : (
|
||||
<div
|
||||
className='tw-card tw-bg-base-100 tw-shadow-xl tw-my-2 tw-w-10'
|
||||
className='tw:card tw:bg-base-100 tw:shadow-xl tw:my-2 tw:w-10'
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div
|
||||
className='tw-card-body hover:tw-bg-slate-300 tw-rounded-2xl tw-p-2 tw-h-10 tw-w-10 tw-transition-all tw-duration-300 hover:tw-cursor-pointer'
|
||||
className='tw:card-body tw:hover:bg-slate-300 tw:rounded-2xl tw:p-2 tw:h-10 tw:w-10 tw:transition-all tw:duration-300 tw:hover:cursor-pointer'
|
||||
onClick={() => setQuestsOpen(true)}
|
||||
>
|
||||
<img src={FistSVG} alt='Quests' className='tw-h-[2em]' />
|
||||
<img src={FistSVG} alt='Quests' className='tw:h-[2em]' />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -103,16 +103,16 @@ export const SearchControl = () => {
|
||||
return (
|
||||
<>
|
||||
{!(windowDimensions.height < 500 && popupOpen && hideSuggestions) && (
|
||||
<div className='tw-w-[calc(100vw-2rem)] tw-max-w-[22rem] '>
|
||||
<div className='tw-flex tw-flex-row'>
|
||||
<div className='tw:w-[calc(100vw-2rem)] tw:max-w-[22rem] '>
|
||||
<div className='tw:flex tw:flex-row'>
|
||||
{appState.embedded && <SidebarControl />}
|
||||
<div className='tw-relative'>
|
||||
<div className='tw:relative tw:shrink tw:max-w-69 tw:w-full'>
|
||||
<input
|
||||
type='text'
|
||||
placeholder='search ...'
|
||||
autoComplete='off'
|
||||
value={value}
|
||||
className='tw-input tw-input-bordered tw-grow tw-shadow-xl tw-rounded-lg tw-pr-12'
|
||||
className='tw:input tw:input-bordered tw:h-12 tw:grow tw:shadow-xl tw:rounded-box tw:pr-12 tw:w-full'
|
||||
ref={searchInput}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
onFocus={() => {
|
||||
@ -123,7 +123,7 @@ export const SearchControl = () => {
|
||||
/>
|
||||
{value.length > 0 && (
|
||||
<button
|
||||
className='tw-btn tw-btn-sm tw-btn-circle tw-absolute tw-right-2 tw-top-2'
|
||||
className='tw:btn tw:btn-sm tw:btn-circle tw:absolute tw:right-2 tw:top-2'
|
||||
onClick={() => setValue('')}
|
||||
>
|
||||
✕
|
||||
@ -140,13 +140,13 @@ export const SearchControl = () => {
|
||||
value.length === 0 ? (
|
||||
''
|
||||
) : (
|
||||
<div className='tw-card tw-card-body tw-bg-base-100 tw-p-4 tw-mt-2 tw-shadow-xl tw-overflow-y-auto tw-max-h-[calc(100dvh-152px)] tw-absolute tw-z-3000'>
|
||||
<div className='tw:card tw:card-body tw:bg-base-100 tw:p-4 tw:mt-2 tw:shadow-xl tw:overflow-y-auto tw:max-h-[calc(100dvh-152px)] tw:absolute tw:z-3000 tw:w-83'>
|
||||
{tagsResults.length > 0 && (
|
||||
<div className='tw-flex tw-flex-wrap'>
|
||||
<div className='tw:flex tw:flex-wrap'>
|
||||
{tagsResults.slice(0, 3).map((tag) => (
|
||||
<div
|
||||
key={tag.name}
|
||||
className='tw-rounded-2xl tw-text-white tw-p-1 tw-px-4 tw-shadow-md tw-card tw-mr-2 tw-mb-2 tw-cursor-pointer'
|
||||
className='tw:rounded-2xl tw:text-white tw:p-1 tw:px-4 tw:shadow-md tw:card tw:mr-2 tw:mb-2 tw:cursor-pointer'
|
||||
style={{ backgroundColor: tag.color }}
|
||||
onClick={() => {
|
||||
addFilterTag(tag)
|
||||
@ -159,12 +159,12 @@ export const SearchControl = () => {
|
||||
)}
|
||||
|
||||
{itemsResults.length > 0 && tagsResults.length > 0 && (
|
||||
<hr className='tw-opacity-50'></hr>
|
||||
<hr className='tw:opacity-50'></hr>
|
||||
)}
|
||||
{itemsResults.slice(0, 5).map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className='tw-cursor-pointer hover:tw-font-bold tw-flex tw-flex-row'
|
||||
className='tw:cursor-pointer tw:hover:font-bold tw:flex tw:flex-row'
|
||||
onClick={() => {
|
||||
const marker = Object.entries(leafletRefs).find((r) => r[1].item === item)?.[1]
|
||||
.marker
|
||||
@ -180,7 +180,7 @@ export const SearchControl = () => {
|
||||
{item.layer?.menuIcon ? (
|
||||
<SVG
|
||||
src={item.layer.menuIcon}
|
||||
className='tw-text-current tw-mr-2 tw-mt-0 tw-w-5'
|
||||
className='tw:text-current tw:mr-2 tw:mt-0 tw:w-5'
|
||||
preProcessor={(code: string): string => {
|
||||
code = code.replace(/fill=".*?"/g, 'fill="currentColor"')
|
||||
code = code.replace(/stroke=".*?"/g, 'stroke="currentColor"')
|
||||
@ -188,13 +188,13 @@ export const SearchControl = () => {
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div className='tw-w-5' />
|
||||
<div className='tw:w-5' />
|
||||
)}
|
||||
<div>
|
||||
<div className='tw-text-sm tw-overflow-hidden tw-text-ellipsis tw-whitespace-nowrap tw-max-w-[17rem]'>
|
||||
<div className='tw:text-sm tw:overflow-hidden tw:text-ellipsis tw:whitespace-nowrap tw:max-w-[17rem]'>
|
||||
{item.name}
|
||||
</div>
|
||||
<div className='tw-text-xs tw-overflow-hidden tw-text-ellipsis tw-whitespace-nowrap tw-max-w-[17rem]'>
|
||||
<div className='tw:text-xs tw:overflow-hidden tw:text-ellipsis tw:whitespace-nowrap tw:max-w-[17rem]'>
|
||||
{item.text}
|
||||
</div>
|
||||
</div>
|
||||
@ -202,11 +202,11 @@ export const SearchControl = () => {
|
||||
))}
|
||||
{Array.from(geoResults).length > 0 &&
|
||||
(itemsResults.length > 0 || tagsResults.length > 0) && (
|
||||
<hr className='tw-opacity-50'></hr>
|
||||
<hr className='tw:opacity-50'></hr>
|
||||
)}
|
||||
{Array.from(geoResults).map((geo) => (
|
||||
<div
|
||||
className='tw-flex tw-flex-row hover:tw-font-bold tw-cursor-pointer'
|
||||
className='tw:flex tw:flex-row tw:hover:font-bold tw:cursor-pointer'
|
||||
key={Math.random()}
|
||||
onClick={() => {
|
||||
searchInput.current?.blur()
|
||||
@ -215,7 +215,7 @@ export const SearchControl = () => {
|
||||
})
|
||||
.addTo(map)
|
||||
.bindPopup(
|
||||
`<h3 class="tw-text-base tw-font-bold">${geo?.properties.name ? geo?.properties.name : value}<h3>${capitalizeFirstLetter(geo?.properties?.osm_value)}`,
|
||||
`<h3 class="tw:text-base tw:font-bold">${geo?.properties.name ? geo?.properties.name : value}<h3>${capitalizeFirstLetter(geo?.properties?.osm_value)}`,
|
||||
)
|
||||
.openPopup()
|
||||
.addEventListener('popupclose', (e) => {
|
||||
@ -238,12 +238,12 @@ export const SearchControl = () => {
|
||||
hide()
|
||||
}}
|
||||
>
|
||||
<MagnifyingGlassIcon className='tw-text-current tw-mr-2 tw-mt-0 tw-w-5' />
|
||||
<MagnifyingGlassIcon className='tw:text-current tw:mr-2 tw:mt-0 tw:w-5' />
|
||||
<div>
|
||||
<div className='tw-text-sm tw-overflow-hidden tw-text-ellipsis tw-whitespace-nowrap tw-max-w-[17rem]'>
|
||||
<div className='tw:text-sm tw:overflow-hidden tw:text-ellipsis tw:whitespace-nowrap tw:max-w-[17rem]'>
|
||||
{geo?.properties.name ? geo?.properties.name : value}
|
||||
</div>
|
||||
<div className='tw-text-xs tw-overflow-hidden tw-text-ellipsis tw-whitespace-nowrap tw-max-w-[17rem]'>
|
||||
<div className='tw:text-xs tw:overflow-hidden tw:text-ellipsis tw:whitespace-nowrap tw:max-w-[17rem]'>
|
||||
{geo?.properties?.city && `${capitalizeFirstLetter(geo?.properties?.city)}, `}{' '}
|
||||
{geo?.properties?.osm_value &&
|
||||
geo?.properties?.osm_value !== 'yes' &&
|
||||
@ -261,7 +261,7 @@ export const SearchControl = () => {
|
||||
))}
|
||||
{isGeoCoordinate(value) && (
|
||||
<div
|
||||
className='tw-flex tw-flex-row hover:tw-font-bold tw-cursor-pointer'
|
||||
className='tw:flex tw:flex-row tw:hover:font-bold tw:cursor-pointer'
|
||||
onClick={() => {
|
||||
marker(
|
||||
new LatLng(extractCoordinates(value)![0], extractCoordinates(value)![1]),
|
||||
@ -271,7 +271,7 @@ export const SearchControl = () => {
|
||||
)
|
||||
.addTo(map)
|
||||
.bindPopup(
|
||||
`<h3 class="tw-text-base tw-font-bold">${extractCoordinates(value)![0]}, ${extractCoordinates(value)![1]}</h3>`,
|
||||
`<h3 class="tw:text-base tw:font-bold">${extractCoordinates(value)![0]}, ${extractCoordinates(value)![1]}</h3>`,
|
||||
)
|
||||
.openPopup()
|
||||
.addEventListener('popupclose', (e) => {
|
||||
@ -285,12 +285,12 @@ export const SearchControl = () => {
|
||||
)
|
||||
}}
|
||||
>
|
||||
<FlagIcon className='tw-text-current tw-mr-2 tw-mt-0 tw-w-4' />
|
||||
<FlagIcon className='tw:text-current tw:mr-2 tw:mt-0 tw:w-4' />
|
||||
<div>
|
||||
<div className='tw-text-sm tw-overflow-hidden tw-text-ellipsis tw-whitespace-nowrap tw-max-w-[17rem]'>
|
||||
<div className='tw:text-sm tw:overflow-hidden tw:text-ellipsis tw:whitespace-nowrap tw:max-w-[17rem]'>
|
||||
{value}
|
||||
</div>
|
||||
<div className='tw-text-xs tw-overflow-hidden tw-text-ellipsis tw-whitespace-nowrap tw-max-w-[17rem]'>
|
||||
<div className='tw:text-xs tw:overflow-hidden tw:text-ellipsis tw:whitespace-nowrap tw:max-w-[17rem]'>
|
||||
{'Coordiante'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
import Bars3Icon from '@heroicons/react/16/solid/Bars3Icon'
|
||||
|
||||
import { useAppState, useSetAppState } from '#components/AppShell/hooks/useAppState'
|
||||
|
||||
// Converts leaflet.locatecontrol to a React Component
|
||||
export const SidebarControl = () => {
|
||||
const appState = useAppState()
|
||||
const setAppState = useSetAppState()
|
||||
const toggleSidebar = () => {
|
||||
setAppState({ sideBarOpen: !appState.sideBarOpen })
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className='tw-card tw-bg-base-100 tw-shadow-xl tw-items-center tw-justify-center hover:tw-bg-slate-300 hover:tw-cursor-pointer tw-transition-all tw-duration-300 tw-mr-2 tw-h-12 tw-w-12 '>
|
||||
<div className='tw-card-body tw-card tw-p-0'>
|
||||
<button
|
||||
className='tw-btn tw-btn-square tw-btn-ghost tw-rounded-2xl'
|
||||
data-te-sidenav-toggle-ref
|
||||
data-te-target='#sidenav'
|
||||
aria-controls='#sidenav'
|
||||
aria-haspopup='true'
|
||||
>
|
||||
<Bars3Icon className='tw-inline-block tw-w-5 tw-h-5' />
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className='tw:card tw:justify-center tw:items-center tw:bg-base-100 tw:flex-none tw:shadow-xl tw:px-0 tw:hover:bg-slate-300 tw:hover:cursor-pointer tw:transition-all tw:duration-300 tw:mr-2 tw:h-12 tw:w-12 '
|
||||
onClick={() => toggleSidebar()}
|
||||
>
|
||||
<Bars3Icon className='tw:inline-block tw:w-5 tw:h-5' />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
@ -6,16 +6,16 @@ export const TagsControl = () => {
|
||||
const removeFilterTag = useRemoveFilterTag()
|
||||
|
||||
return (
|
||||
<div className='tw-flex tw-flex-wrap tw-mt-4 tw-w-[calc(100vw-2rem)] tw-max-w-xs'>
|
||||
<div className='tw:flex tw:flex-wrap tw:mt-4 tw:w-[calc(100vw-2rem)] tw:max-w-xs'>
|
||||
{filterTags.map((tag) => (
|
||||
<div
|
||||
key={tag.id}
|
||||
className='tw-rounded-2xl tw-text-white tw-p-2 tw-px-4 tw-shadow-xl tw-card tw-mr-2 tw-mb-2'
|
||||
className='tw:rounded-2xl tw:text-white tw:p-2 tw:px-4 tw:shadow-xl tw:card tw:mr-2 tw:mb-2'
|
||||
style={{ backgroundColor: tag.color }}
|
||||
>
|
||||
<div className='tw-card-actions tw-justify-end'>
|
||||
<div className='tw:card-actions tw:justify-end'>
|
||||
<label
|
||||
className='tw-btn tw-btn-xs tw-btn-circle tw-absolute tw--right-2 tw--top-2 tw-bg-white tw-text-gray-600'
|
||||
className='tw:btn tw:btn-xs tw:btn-circle tw:absolute tw:-right-2 tw:-top-2 tw:bg-white tw:text-gray-600'
|
||||
onClick={() => removeFilterTag(tag.name)}
|
||||
>
|
||||
✕
|
||||
|
||||
@ -155,10 +155,10 @@ export function ItemFormPopup(props: ItemFormPopupProps) {
|
||||
>
|
||||
<form ref={formRef} onReset={resetPopup} autoComplete='off' onSubmit={(e) => handleSubmit(e)}>
|
||||
{props.item ? (
|
||||
<div className='tw-h-3'></div>
|
||||
<div className='tw:h-3'></div>
|
||||
) : (
|
||||
<div className='tw-flex tw-justify-center'>
|
||||
<b className='tw-text-xl tw-text-center tw-font-bold'>{props.layer.menuText}</b>
|
||||
<div className='tw:flex tw:justify-center'>
|
||||
<b className='tw:text-xl tw:text-center tw:font-bold'>{props.layer.menuText}</b>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -190,21 +190,21 @@ export function ItemFormPopup(props: ItemFormPopupProps) {
|
||||
placeholder='Text'
|
||||
dataField='text'
|
||||
defaultValue={props.item?.text ?? ''}
|
||||
inputStyle='tw-h-40 tw-mt-5'
|
||||
inputStyle='tw:h-40 tw:mt-5'
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className='tw-flex tw-justify-center'>
|
||||
<div className='tw:flex tw:justify-center'>
|
||||
<button
|
||||
className={
|
||||
spinner
|
||||
? 'tw-btn tw-btn-disabled tw-mt-5 tw-place-self-center'
|
||||
: 'tw-btn tw-mt-5 tw-place-self-center'
|
||||
? 'tw:btn tw:btn-disabled tw:mt-5 tw:place-self-center'
|
||||
: 'tw:btn tw:mt-5 tw:place-self-center'
|
||||
}
|
||||
type='submit'
|
||||
>
|
||||
{spinner ? <span className='tw-loading tw-loading-spinner'></span> : 'Save'}
|
||||
{spinner ? <span className='tw:loading tw:loading-spinner'></span> : 'Save'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -57,9 +57,7 @@ export function HeaderView({
|
||||
|
||||
const [imageLoaded, setImageLoaded] = useState(false)
|
||||
|
||||
const avatar =
|
||||
item.image &&
|
||||
appState.assetsApi.url + item.image + `${big ? '?width=160&heigth=160' : '?width=80&heigth=80'}`
|
||||
const avatar = item.image && appState.assetsApi.url + item.image + '?width=160&heigth=160'
|
||||
const title = item.name
|
||||
const subtitle = item.subname
|
||||
|
||||
@ -74,18 +72,18 @@ export function HeaderView({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='tw-flex tw-flex-row'>
|
||||
<div className={'tw-grow tw-max-w-[calc(100%-60px)] }'}>
|
||||
<div className='tw:flex tw:flex-row'>
|
||||
<div className={'tw:grow tw:max-w-[calc(100%-60px)] }'}>
|
||||
<div className='flex items-center'>
|
||||
{avatar && (
|
||||
<div className='tw-avatar'>
|
||||
<div className='tw:avatar'>
|
||||
<div
|
||||
className={`${
|
||||
big ? 'tw-w-20' : 'tw-w-10'
|
||||
} tw-inline tw-items-center tw-justify-center overflow-hidden`}
|
||||
big ? 'tw:w-20' : 'tw:w-10'
|
||||
} tw:inline tw:items-center tw:justify-center overflow-hidden`}
|
||||
>
|
||||
<img
|
||||
className={'tw-w-full tw-h-full tw-object-cover tw-rounded-full'}
|
||||
className={'tw:w-full tw:h-full tw:object-cover tw:rounded-full'}
|
||||
src={avatar}
|
||||
alt={item.name + ' logo'}
|
||||
onLoad={() => setImageLoaded(true)}
|
||||
@ -93,53 +91,53 @@ export function HeaderView({
|
||||
style={{ display: imageLoaded ? 'block' : 'none' }}
|
||||
/>
|
||||
{!imageLoaded && (
|
||||
<div className='tw-w-full tw-h-full tw-bg-gray-200 tw-rounded-full' />
|
||||
<div className='tw:w-full tw:h-full tw:bg-gray-200 tw:rounded-full' />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={`${avatar ? 'tw-ml-2' : ''} tw-overflow-hidden`}>
|
||||
<div className={`${avatar ? 'tw:ml-2' : ''} tw:overflow-hidden`}>
|
||||
<div
|
||||
className={`${big ? 'xl:tw-text-3xl tw-text-2xl' : 'tw-text-xl'} tw-font-semibold tw-truncate`}
|
||||
className={`${big ? 'tw:xl:text-3xl tw:text-2xl' : 'tw:text-xl'} tw:font-semibold tw:truncate`}
|
||||
title={title}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
{showAddress && address && !hideSubname && (
|
||||
<div className={`tw-text-xs tw-text-gray-500 ${truncateSubname && 'tw-truncate'}`}>
|
||||
<div className={`tw:text-xs tw:text-gray-500 ${truncateSubname && 'tw:truncate'}`}>
|
||||
{address}
|
||||
</div>
|
||||
)}
|
||||
{subtitle && !hideSubname && (
|
||||
<div className={`tw-text-xs tw-text-gray-500 ${truncateSubname && 'tw-truncate'}`}>
|
||||
<div className={`tw:text-xs tw:opacity-50 ${truncateSubname && 'tw:truncate'}`}>
|
||||
{subtitle}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div onClick={(e) => e.stopPropagation()} className={`${big ? 'tw-mt-5' : 'tw-mt-1'}`}>
|
||||
<div onClick={(e) => e.stopPropagation()} className={`${big ? 'tw:mt-5' : 'tw:mt-1'}`}>
|
||||
{(api?.deleteItem || item.layer?.api?.updateItem) &&
|
||||
(hasUserPermission(api?.collectionName!, 'delete', item) ||
|
||||
hasUserPermission(api?.collectionName!, 'update', item)) &&
|
||||
!hideMenu && (
|
||||
<div className='tw-dropdown tw-dropdown-bottom'>
|
||||
<div className='tw:dropdown tw:dropdown-bottom'>
|
||||
<label
|
||||
tabIndex={0}
|
||||
className='tw-bg-base-100 tw-btn tw-m-1 tw-leading-3 tw-border-none tw-min-h-0 tw-h-6'
|
||||
className='tw:bg-base-100 tw:btn tw:m-1 tw:leading-3 tw:border-none tw:min-h-0 tw:h-6'
|
||||
>
|
||||
<EllipsisVerticalIcon className='tw-h-5 tw-w-5' />
|
||||
<EllipsisVerticalIcon className='tw:h-5 tw:w-5' />
|
||||
</label>
|
||||
<ul
|
||||
tabIndex={0}
|
||||
className='tw-dropdown-content tw-menu tw-p-2 tw-shadow tw-bg-base-100 tw-rounded-box tw-z-1000'
|
||||
className='tw:dropdown-content tw:menu tw:p-2 tw:shadow tw:bg-base-100 tw:rounded-box tw:z-1000'
|
||||
>
|
||||
{api?.updateItem &&
|
||||
hasUserPermission(api.collectionName!, 'update', item) &&
|
||||
editCallback && (
|
||||
<li>
|
||||
<a
|
||||
className='!tw-text-base-content tw-cursor-pointer'
|
||||
className='tw:text-base-content! tw:cursor-pointer'
|
||||
onClick={(e) =>
|
||||
item.layer?.customEditLink
|
||||
? navigate(
|
||||
@ -148,7 +146,7 @@ export function HeaderView({
|
||||
: editCallback(e)
|
||||
}
|
||||
>
|
||||
<PencilIcon className='tw-h-5 tw-w-5' />
|
||||
<PencilIcon className='tw:h-5 tw:w-5' />
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
@ -157,10 +155,10 @@ export function HeaderView({
|
||||
setPositionCallback && (
|
||||
<li>
|
||||
<a
|
||||
className='!tw-text-base-content tw-cursor-pointer'
|
||||
className='tw:text-base-content! tw:cursor-pointer'
|
||||
onClick={setPositionCallback}
|
||||
>
|
||||
<SVG src={TargetDotSVG} className='tw-w-5 tw-h-5' />
|
||||
<SVG src={TargetDotSVG} className='tw:w-5 tw:h-5' />
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
@ -168,11 +166,11 @@ export function HeaderView({
|
||||
hasUserPermission(api.collectionName!, 'delete', item) &&
|
||||
deleteCallback && (
|
||||
<li>
|
||||
<a className='tw-cursor-pointer !tw-text-error' onClick={openDeleteModal}>
|
||||
<a className='tw:cursor-pointer tw:text-error!' onClick={openDeleteModal}>
|
||||
{loading ? (
|
||||
<span className='tw-loading tw-loading-spinner tw-loading-sm'></span>
|
||||
<span className='tw:loading tw:loading-spinner tw:loading-sm'></span>
|
||||
) : (
|
||||
<TrashIcon className='tw-h-5 tw-w-5' />
|
||||
<TrashIcon className='tw:h-5 tw:w-5' />
|
||||
)}
|
||||
</a>
|
||||
</li>
|
||||
@ -192,10 +190,10 @@ export function HeaderView({
|
||||
<span>
|
||||
Do you want to delete <b>{item.name}</b>?
|
||||
</span>
|
||||
<div className='tw-grid'>
|
||||
<div className='tw-flex tw-justify-between'>
|
||||
<div className='tw:grid'>
|
||||
<div className='tw:flex tw:justify-between'>
|
||||
<label
|
||||
className='tw-btn tw-mt-4 tw-btn-error'
|
||||
className='tw:btn tw:mt-4 tw:btn-error'
|
||||
onClick={(e) => {
|
||||
deleteCallback(e)
|
||||
setModalOpen(false)
|
||||
@ -203,7 +201,7 @@ export function HeaderView({
|
||||
>
|
||||
Yes
|
||||
</label>
|
||||
<label className='tw-btn tw-mt-4' onClick={() => setModalOpen(false)}>
|
||||
<label className='tw:btn tw:mt-4' onClick={() => setModalOpen(false)}>
|
||||
No
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@ -29,7 +29,7 @@ export const PopupButton = ({
|
||||
style={{
|
||||
backgroundColor: `${item?.color ?? (item && (getItemTags(item) && getItemTags(item)[0] && getItemTags(item)[0].color ? getItemTags(item)[0].color : (item?.layer?.markerDefaultColor ?? '#000')))}`,
|
||||
}}
|
||||
className='tw-btn tw-text-white tw-btn-sm tw-float-right tw-mt-1'
|
||||
className='tw:btn tw:text-white tw:btn-sm tw:float-right tw:mt-1'
|
||||
>
|
||||
{text}
|
||||
</button>
|
||||
|
||||
@ -13,15 +13,15 @@ export const PopupCheckboxInput = ({
|
||||
item?: Item
|
||||
}) => {
|
||||
return (
|
||||
<label htmlFor={item?.id} className='tw-label tw-justify-normal tw-pt-1 tw-pb-1'>
|
||||
<label htmlFor={item?.id} className='tw:label tw:justify-normal tw:pt-1 tw:pb-1'>
|
||||
<input
|
||||
id={item?.id}
|
||||
type='checkbox'
|
||||
name={dataField}
|
||||
className='tw-checkbox tw-checkbox-xs tw-checkbox-success'
|
||||
className='tw:checkbox tw:checkbox-xs tw:checkbox-success'
|
||||
checked={item?.public_edit}
|
||||
/>
|
||||
<span className='tw-text-sm tw-label-text tw-mx-2 tw-cursor-pointer'>{label}</span>
|
||||
<span className='tw:text-sm tw:label-text tw:mx-2 tw:cursor-pointer'>{label}</span>
|
||||
</label>
|
||||
)
|
||||
}
|
||||
|
||||
@ -20,12 +20,12 @@ export const PopupStartEndInput = ({
|
||||
updateEndValue,
|
||||
}: StartEndInputProps) => {
|
||||
return (
|
||||
<div className='tw-grid tw-grid-cols-2 tw-gap-2'>
|
||||
<div className='tw:grid tw:grid-cols-2 tw:gap-2'>
|
||||
<TextInput
|
||||
type='date'
|
||||
placeholder='start'
|
||||
dataField='start'
|
||||
inputStyle='tw-text-sm tw-px-2'
|
||||
inputStyle='tw:text-sm tw:px-2'
|
||||
labelTitle={showLabels ? 'start' : ''}
|
||||
defaultValue={item && item.start ? item.start.substring(0, 10) : ''}
|
||||
autocomplete='one-time-code'
|
||||
@ -35,7 +35,7 @@ export const PopupStartEndInput = ({
|
||||
type='date'
|
||||
placeholder='end'
|
||||
dataField='end'
|
||||
inputStyle='tw-text-sm tw-px-2'
|
||||
inputStyle='tw:text-sm tw:px-2'
|
||||
labelTitle={showLabels ? 'end' : ''}
|
||||
defaultValue={item && item.end ? item.end.substring(0, 10) : ''}
|
||||
autocomplete='one-time-code'
|
||||
|
||||
@ -23,7 +23,7 @@ export const PopupTextInput = ({
|
||||
placeholder={placeholder}
|
||||
inputStyle={style}
|
||||
type='text'
|
||||
containerStyle={'tw-mt-4'}
|
||||
containerStyle={'tw:mt-4'}
|
||||
></TextInput>
|
||||
)
|
||||
}
|
||||
|
||||
@ -8,23 +8,23 @@ import type { Item } from '#types/Item'
|
||||
*/
|
||||
export const StartEndView = ({ item }: { item?: Item }) => {
|
||||
return (
|
||||
<div className='tw-flex tw-flex-row tw-mb-4 tw-mt-1'>
|
||||
<div className='tw-basis-2/5 tw-flex tw-flex-row'>
|
||||
<CalendarIcon className='tw-h-4 tw-w-4 tw-mr-2' />
|
||||
<div className='tw:flex tw:flex-row tw:mb-4 tw:mt-1'>
|
||||
<div className='tw:basis-2/5 tw:flex tw:flex-row'>
|
||||
<CalendarIcon className='tw:h-4 tw:w-4 tw:mr-2' />
|
||||
<time
|
||||
className='tw-align-middle'
|
||||
className='tw:align-middle'
|
||||
dateTime={item && item.start ? item.start.substring(0, 10) : ''}
|
||||
>
|
||||
{item && item.start ? new Date(item.start).toLocaleDateString() : ''}
|
||||
</time>
|
||||
</div>
|
||||
<div className='tw-basis-1/5 tw-place-content-center'>
|
||||
<div className='tw:basis-1/5 tw:place-content-center'>
|
||||
<span>-</span>
|
||||
</div>
|
||||
<div className='tw-basis-2/5 tw-flex tw-flex-row'>
|
||||
<CalendarIcon className='tw-h-4 tw-w-4 tw-mr-2' />
|
||||
<div className='tw:basis-2/5 tw:flex tw:flex-row'>
|
||||
<CalendarIcon className='tw:h-4 tw:w-4 tw:mr-2' />
|
||||
<time
|
||||
className='tw-align-middle'
|
||||
className='tw:align-middle'
|
||||
dateTime={item && item.end ? item.end.substring(0, 10) : ''}
|
||||
>
|
||||
{item && item.end ? new Date(item.end).toLocaleDateString() : ''}
|
||||
|
||||
@ -87,36 +87,36 @@ export const TextView = ({
|
||||
})
|
||||
}
|
||||
|
||||
const CustomH1 = ({ children }) => <h1 className='tw-text-xl tw-font-bold'>{children}</h1>
|
||||
const CustomH1 = ({ children }) => <h1 className='tw:text-xl tw:font-bold'>{children}</h1>
|
||||
|
||||
const CustomH2 = ({ children }) => <h2 className='tw-text-lg tw-font-bold'>{children}</h2>
|
||||
const CustomH2 = ({ children }) => <h2 className='tw:text-lg tw:font-bold'>{children}</h2>
|
||||
|
||||
const CustomH3 = ({ children }) => <h3 className='tw-text-base tw-font-bold'>{children}</h3>
|
||||
const CustomH3 = ({ children }) => <h3 className='tw:text-base tw:font-bold'>{children}</h3>
|
||||
|
||||
const CustomH4 = ({ children }) => <h4 className='tw-text-base tw-font-bold'>{children}</h4>
|
||||
const CustomH4 = ({ children }) => <h4 className='tw:text-base tw:font-bold'>{children}</h4>
|
||||
|
||||
const CustomH5 = ({ children }) => <h5 className='tw-text-sm tw-font-bold'>{children}</h5>
|
||||
const CustomH5 = ({ children }) => <h5 className='tw:text-sm tw:font-bold'>{children}</h5>
|
||||
|
||||
const CustomH6 = ({ children }) => <h6 className='tw-text-sm tw-font-bold'>{children}</h6>
|
||||
const CustomH6 = ({ children }) => <h6 className='tw:text-sm tw:font-bold'>{children}</h6>
|
||||
|
||||
const CustomParagraph = ({ children }) => <p className='!tw-my-2'>{children}</p>
|
||||
const CustomParagraph = ({ children }) => <p className='tw:my-2!'>{children}</p>
|
||||
|
||||
const CustomUnorderdList = ({ children }) => (
|
||||
<ul className='tw-list-disc tw-list-inside'>{children}</ul>
|
||||
<ul className='tw:list-disc tw:list-inside'>{children}</ul>
|
||||
)
|
||||
|
||||
const CustomOrderdList = ({ children }) => (
|
||||
<ol className='tw-list-decimal tw-list-inside'>{children}</ol>
|
||||
<ol className='tw:list-decimal tw:list-inside'>{children}</ol>
|
||||
)
|
||||
|
||||
const CustomHorizontalRow = ({ children }) => <hr className='tw-border-current'>{children}</hr>
|
||||
const CustomHorizontalRow = ({ children }) => <hr className='tw:border-current'>{children}</hr>
|
||||
// eslint-disable-next-line react/prop-types
|
||||
const CustomImage = ({ alt, src, title }) => (
|
||||
<img className='tw-max-w-full tw-rounded tw-shadow' src={src} alt={alt} title={title} />
|
||||
<img className='tw:max-w-full tw:rounded tw:shadow' src={src} alt={alt} title={title} />
|
||||
)
|
||||
|
||||
const CustomExternalLink = ({ href, children }) => (
|
||||
<a className='tw-font-bold tw-underline' href={href} target='_blank' rel='noreferrer'>
|
||||
<a className='tw:font-bold tw:underline' href={href} target='_blank' rel='noreferrer'>
|
||||
{' '}
|
||||
{children}
|
||||
</a>
|
||||
@ -148,7 +148,7 @@ export const TextView = ({
|
||||
// eslint-disable-next-line react/display-name
|
||||
const MemoizedVideoEmbed = memo(({ url }: { url: string }) => (
|
||||
<iframe
|
||||
className='tw-w-full'
|
||||
className='tw:w-full'
|
||||
src={url}
|
||||
allow='fullscreen; picture-in-picture'
|
||||
allowFullScreen
|
||||
@ -157,7 +157,7 @@ export const TextView = ({
|
||||
|
||||
return (
|
||||
<Markdown
|
||||
className={'tw-text-map tw-leading-map tw-text-sm'}
|
||||
className={'tw:text-map tw:leading-map tw:text-sm'}
|
||||
remarkPlugins={[remarkBreaks]}
|
||||
components={{
|
||||
p: CustomParagraph,
|
||||
|
||||
@ -84,7 +84,7 @@ export const ItemViewPopup = forwardRef((props: ItemViewPopupProps, ref: any) =>
|
||||
|
||||
return (
|
||||
<LeafletPopup ref={ref} maxHeight={377} minWidth={275} maxWidth={275} autoPanPadding={[20, 80]}>
|
||||
<div className='tw-bg-base-100 tw-text-base-content'>
|
||||
<div className='tw:bg-base-100 tw:text-base-content'>
|
||||
<HeaderView
|
||||
api={props.item.layer?.api}
|
||||
item={props.item}
|
||||
@ -97,7 +97,7 @@ export const ItemViewPopup = forwardRef((props: ItemViewPopupProps, ref: any) =>
|
||||
}}
|
||||
loading={loading}
|
||||
/>
|
||||
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
|
||||
<div className='tw:overflow-y-auto tw:overflow-x-hidden tw:max-h-64 fade'>
|
||||
{props.children ? (
|
||||
Children.toArray(props.children).map((child) =>
|
||||
isValidElement<{ item: Item; test: string }>(child)
|
||||
@ -108,22 +108,22 @@ export const ItemViewPopup = forwardRef((props: ItemViewPopupProps, ref: any) =>
|
||||
<TextView text={props.item.text} itemId={props.item.id} />
|
||||
)}
|
||||
</div>
|
||||
<div className='tw-flex -tw-mb-1 tw-flex-row tw-mr-2 tw-mt-1'>
|
||||
<div className='tw:flex tw:-mb-1 tw:flex-row tw:mr-2 tw:mt-1'>
|
||||
{infoExpanded ? (
|
||||
<p
|
||||
className={'tw-italic tw-min-h-[21px] !tw-my-0 tw-text-gray-500'}
|
||||
className={'tw:italic tw:min-h-[21px] tw:my-0! tw:opacity-50'}
|
||||
>{`${props.item.date_updated && props.item.date_updated !== props.item.date_created ? 'updated' : 'posted'} ${props.item && props.item.user_created && props.item.user_created.first_name ? `by ${props.item.user_created.first_name}` : ''} ${props.item.date_updated ? timeAgo(props.item.date_updated) : timeAgo(props.item.date_created!)}`}</p>
|
||||
) : (
|
||||
<p
|
||||
className='!tw-my-0 tw-min-h-[21px] tw-font-bold tw-cursor-pointer tw-text-gray-500'
|
||||
className='tw:my-0! tw:min-h-[21px] tw:font-bold tw:cursor-pointer tw:text-gray-500'
|
||||
onClick={() => setInfoExpanded(true)}
|
||||
>
|
||||
ⓘ
|
||||
</p>
|
||||
)}
|
||||
<div className='tw-grow'></div>
|
||||
<div className='tw:grow'></div>
|
||||
{
|
||||
//* * <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="tw-place-self-end tw-w-4 tw-h-4 tw-mb-1 tw-cursor-pointer"><path strokeLinecap="round" strokeLinejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" /></svg> */
|
||||
//* * <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="tw:place-self-end tw:w-4 tw:h-4 tw:mb-1 tw:cursor-pointer"><path strokeLinecap="round" strokeLinejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" /></svg> */
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
export const SelectPosition = ({ setSelectNewItemPosition }: { setSelectNewItemPosition }) => {
|
||||
return (
|
||||
<div className='tw-animate-pulseGrow tw-button tw-z-1000 tw-absolute tw-right-5 tw-top-4 tw-drop-shadow-md'>
|
||||
<div className='tw:animate-pulseGrow tw:button tw:z-1000 tw:absolute tw:right-5 tw:top-4 tw:drop-shadow-md'>
|
||||
<label
|
||||
className='tw-btn tw-btn-sm tw-rounded-2xl tw-btn-circle tw-btn-ghost hover:tw-bg-transparent tw-absolute tw-right-0 tw-top-0 tw-text-gray-600'
|
||||
className='tw:btn tw:btn-sm tw:rounded-2xl tw:btn-circle tw:btn-ghost tw:hover:bg-transparent tw:absolute tw:right-0 tw:top-0 tw:text-gray-600'
|
||||
onClick={() => {
|
||||
setSelectNewItemPosition(null)
|
||||
}}
|
||||
>
|
||||
<p className='tw-text-center '>✕</p>
|
||||
<p className='tw:text-center '>✕</p>
|
||||
</label>
|
||||
<div className='tw-alert tw-bg-base-100 tw-text-base-content'>
|
||||
<div className='tw:alert tw:bg-base-100 tw:text-base-content'>
|
||||
<div>
|
||||
<span className='tw-text-lg'>Select position on the map!</span>
|
||||
<span className='tw:text-lg'>Select position on the map!</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -51,6 +51,8 @@ function UtopiaMap({
|
||||
showFilterControl = false,
|
||||
showGratitudeControl = false,
|
||||
showLayerControl = true,
|
||||
showThemeControl = false,
|
||||
defaultTheme,
|
||||
donationWidget,
|
||||
}: {
|
||||
/** height of the map (default '500px') */
|
||||
@ -71,6 +73,10 @@ function UtopiaMap({
|
||||
showLayerControl?: boolean
|
||||
/** show the layer control widget (default true) */
|
||||
showGratitudeControl?: boolean
|
||||
/** show a widget to switch the theme */
|
||||
showThemeControl?: boolean
|
||||
/** the defaut theme */
|
||||
defaultTheme?: string
|
||||
/** ask to donate to the Utopia Project OpenCollective campaign (default false) */
|
||||
donationWidget?: boolean
|
||||
}) {
|
||||
@ -89,6 +95,8 @@ function UtopiaMap({
|
||||
showGratitudeControl={showGratitudeControl}
|
||||
showLayerControl={showLayerControl}
|
||||
donationWidget={donationWidget}
|
||||
showThemeControl={showThemeControl}
|
||||
defaultTheme={defaultTheme}
|
||||
>
|
||||
{children}
|
||||
</UtopiaMapInner>
|
||||
|
||||
@ -12,6 +12,8 @@ import MarkerClusterGroup from 'react-leaflet-cluster'
|
||||
import { Outlet, useLocation } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import { useSetAppState } from '#components/AppShell/hooks/useAppState'
|
||||
import { useTheme } from '#components/AppShell/hooks/useTheme'
|
||||
import { containsUUID } from '#utils/ContainsUUID'
|
||||
|
||||
import { useClusterRef, useSetClusterRef } from './hooks/useClusterRef'
|
||||
@ -42,6 +44,8 @@ export function UtopiaMapInner({
|
||||
showFilterControl = false,
|
||||
showGratitudeControl = false,
|
||||
showLayerControl = true,
|
||||
showThemeControl = false,
|
||||
defaultTheme = '',
|
||||
donationWidget,
|
||||
}: {
|
||||
children?: React.ReactNode
|
||||
@ -50,6 +54,8 @@ export function UtopiaMapInner({
|
||||
showLayerControl?: boolean
|
||||
showGratitudeControl?: boolean
|
||||
donationWidget?: boolean
|
||||
showThemeControl?: boolean
|
||||
defaultTheme?: string
|
||||
}) {
|
||||
const selectNewItemPosition = useSelectPosition()
|
||||
const setSelectNewItemPosition = useSetSelectPosition()
|
||||
@ -58,6 +64,8 @@ export function UtopiaMapInner({
|
||||
const setMapClicked = useSetMapClicked()
|
||||
const [itemFormPopup, setItemFormPopup] = useState<ItemFormPopupProps | null>(null)
|
||||
|
||||
useTheme(defaultTheme)
|
||||
|
||||
const layers = useLayers()
|
||||
const addVisibleLayer = useAddVisibleLayer()
|
||||
const leafletRefs = useLeafletRefs()
|
||||
@ -70,6 +78,12 @@ export function UtopiaMapInner({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [layers])
|
||||
|
||||
const setAppState = useSetAppState()
|
||||
|
||||
useEffect(() => {
|
||||
setAppState({ showThemeControl })
|
||||
}, [setAppState, showThemeControl])
|
||||
|
||||
const init = useRef(false)
|
||||
useEffect(() => {
|
||||
if (!init.current) {
|
||||
@ -86,7 +100,7 @@ export function UtopiaMapInner({
|
||||
}
|
||||
/>
|
||||
<a href='https://opencollective.com/utopia-project'>
|
||||
<div className='tw-btn tw-btn-sm tw-float-right tw-btn-primary'>Donate</div>
|
||||
<div className='tw:btn tw:btn-sm tw:float-right tw:btn-primary'>Donate</div>
|
||||
</a>
|
||||
</div>
|
||||
</>,
|
||||
@ -187,7 +201,7 @@ export function UtopiaMapInner({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`tw-h-full ${selectNewItemPosition != null ? 'crosshair-cursor-enabled' : ''}`}>
|
||||
<div className={`tw:h-full ${selectNewItemPosition != null ? 'crosshair-cursor-enabled' : ''}`}>
|
||||
<Outlet />
|
||||
<Control position='topLeft' zIndex='1000' absolute>
|
||||
<SearchControl />
|
||||
|
||||
@ -157,10 +157,10 @@ export function ProfileForm() {
|
||||
<>
|
||||
<MapOverlayPage
|
||||
backdrop
|
||||
className='tw-mx-4 tw-mt-4 tw-mb-4 tw-overflow-x-hidden tw-w-[calc(100%-32px)] md:tw-w-[calc(50%-32px)] tw-max-w-3xl !tw-left-auto tw-top-0 tw-bottom-0'
|
||||
className='tw:mx-4 tw:mt-4 tw:mb-4 tw:overflow-x-hidden tw:w-[calc(100%-32px)] tw:md:w-[calc(50%-32px)] tw:max-w-3xl tw:left-auto! tw:top-0 tw:bottom-0'
|
||||
>
|
||||
<form
|
||||
className='tw-h-full'
|
||||
className='tw:h-full'
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault()
|
||||
void onUpdateItem(
|
||||
@ -177,7 +177,7 @@ export function ProfileForm() {
|
||||
)
|
||||
}}
|
||||
>
|
||||
<div className='tw-flex tw-flex-col tw-h-full'>
|
||||
<div className='tw:flex tw:flex-col tw:h-full'>
|
||||
<FormHeader item={item} state={state} setState={setState} />
|
||||
|
||||
{template === 'onepager' && (
|
||||
@ -203,9 +203,9 @@ export function ProfileForm() {
|
||||
></TabsForm>
|
||||
)}
|
||||
|
||||
<div className='tw-mt-4'>
|
||||
<div className='tw:mt-4 tw:flex-none'>
|
||||
<button
|
||||
className={loading ? ' tw-loading tw-btn tw-float-right' : 'tw-btn tw-float-right'}
|
||||
className={`${loading ? ' tw:loading tw:btn tw:float-right' : 'tw:btn tw:float-right'}`}
|
||||
type='submit'
|
||||
style={{
|
||||
// We could refactor this, it is used several times at different locations
|
||||
|
||||
@ -174,10 +174,10 @@ export function ProfileView({ attestationApi }: { attestationApi?: ItemsApi<any>
|
||||
{item && (
|
||||
<MapOverlayPage
|
||||
key={item.id}
|
||||
className={`!tw-p-0 tw-mx-4 tw-mt-4 tw-mb-4 md:tw-w-[calc(50%-32px)] tw-w-[calc(100%-32px)] tw-min-w-80 tw-max-w-3xl !tw-left-0 sm:!tw-left-auto tw-top-0 tw-bottom-0 tw-transition-opacity tw-duration-500 ${!selectPosition ? 'tw-opacity-100 tw-pointer-events-auto' : 'tw-opacity-0 tw-pointer-events-none'}`}
|
||||
className={`tw:p-0! tw:overflow-scroll tw:m-4! tw:md:w-[calc(50%-32px)] tw:w-[calc(100%-32px)] tw:min-w-80 tw:max-w-3xl tw:left-0! tw:sm:left-auto! tw:top-0 tw:bottom-0 tw:transition-opacity tw:duration-500 ${!selectPosition ? 'tw:opacity-100 tw:pointer-events-auto' : 'tw:opacity-0 tw:pointer-events-none'}`}
|
||||
>
|
||||
<>
|
||||
<div className={'tw-px-6 tw-pt-6'}>
|
||||
<div className={'tw:px-6 tw:pt-6'}>
|
||||
<HeaderView
|
||||
api={item.layer?.api}
|
||||
item={item}
|
||||
|
||||
@ -54,11 +54,11 @@ export function ActionButton({
|
||||
<>
|
||||
{hasUserPermission(collection, 'update', item) && (
|
||||
<>
|
||||
<div className={`tw-absolute tw-right-4 tw-bottom-4 tw-flex tw-flex-col ${customStyle}`}>
|
||||
<div className={`tw:absolute tw:right-6 tw:bottom-4 tw:flex tw:flex-col ${customStyle}`}>
|
||||
{triggerItemSelected && (
|
||||
<button
|
||||
tabIndex={0}
|
||||
className='tw-z-500 tw-btn tw-btn-circle tw-shadow'
|
||||
className='tw:z-500 tw:btn tw:btn-circle tw:shadow'
|
||||
onClick={() => {
|
||||
setModalOpen(true)
|
||||
}}
|
||||
@ -67,13 +67,13 @@ export function ActionButton({
|
||||
color: '#fff',
|
||||
}}
|
||||
>
|
||||
<LinkIcon className='tw-h-5 tw-w-5 tw-stroke-[2.5]' />
|
||||
<LinkIcon className='tw:h-5 tw:w-5 tw:stroke-[2.5]' />
|
||||
</button>
|
||||
)}
|
||||
{triggerAddButton && (
|
||||
<button
|
||||
tabIndex={0}
|
||||
className='tw-z-500 tw-btn tw-btn-circle tw-shadow tw-mt-2'
|
||||
className='tw:z-500 tw:btn tw:btn-circle tw:shadow tw:mt-2'
|
||||
onClick={() => {
|
||||
triggerAddButton()
|
||||
}}
|
||||
@ -82,7 +82,7 @@ export function ActionButton({
|
||||
color: '#fff',
|
||||
}}
|
||||
>
|
||||
<PlusIcon className='tw-w-5 tw-h-5 tw-stroke-[2.5]' />
|
||||
<PlusIcon className='tw:w-5 tw:h-5 tw:stroke-[2.5]' />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@ -90,17 +90,17 @@ export function ActionButton({
|
||||
title={'Select'}
|
||||
isOpened={modalOpen}
|
||||
onClose={() => setModalOpen(false)}
|
||||
className='tw-w-xl sm:tw-w-2xl tw-min-h-80 tw-bg-base-200'
|
||||
className='tw:w-xl tw:sm:w-2xl tw:min-h-80 tw:bg-base-200'
|
||||
>
|
||||
<TextInput
|
||||
defaultValue=''
|
||||
placeholder='🔍 Search'
|
||||
containerStyle='lg:col-span-2 tw-m-4 '
|
||||
containerStyle='lg:col-span-2 tw:m-4 '
|
||||
updateFormValue={(val) => {
|
||||
setSearch(val)
|
||||
}}
|
||||
></TextInput>
|
||||
<div className='tw-grid tw-grid-cols-1 sm:tw-grid-cols-2'>
|
||||
<div className='tw:grid tw:grid-cols-1 tw:sm:grid-cols-2'>
|
||||
{filterdItems
|
||||
.filter((item) => {
|
||||
return search === ''
|
||||
@ -110,7 +110,7 @@ export function ActionButton({
|
||||
.map((i) => (
|
||||
<div
|
||||
key={i.id}
|
||||
className='tw-cursor-pointer tw-card tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl tw-bg-base-100 tw-text-base-content tw-mx-4 tw-p-4 tw-mb-4 tw-h-fit'
|
||||
className='tw:cursor-pointer tw:card tw:border-[1px] tw:border-base-300 tw:card-body tw:shadow-xl tw:bg-base-100 tw:text-base-content tw:mx-4 tw:p-4 tw:mb-4 tw:h-fit'
|
||||
onClick={() => {
|
||||
triggerItemSelected(i.id)
|
||||
setModalOpen(false)
|
||||
|
||||
@ -166,28 +166,28 @@ export const AvatarWidget: React.FC<AvatarWidgetProps> = ({ avatar, setAvatar })
|
||||
<input
|
||||
type='file'
|
||||
accept='image/*'
|
||||
className='tw-file-input tw-w-full tw-max-w-xs'
|
||||
className='tw:file-input tw:w-full tw:max-w-xs'
|
||||
onChange={onImageChange}
|
||||
/>
|
||||
<div className='button tw-btn tw-btn-lg tw-btn-circle tw-animate-none'>
|
||||
<ArrowUpTrayIcon className='tw-w-6 tw-h-6' />
|
||||
<div className='button tw:btn tw:btn-lg tw:btn-circle tw:animate-none'>
|
||||
<ArrowUpTrayIcon className='tw:w-6 tw:h-6' />
|
||||
</div>
|
||||
{avatar ? (
|
||||
<div className='tw-h-20 tw-w-20'>
|
||||
<div className='tw:h-20 tw:w-20'>
|
||||
<img
|
||||
src={appState.assetsApi.url + avatar}
|
||||
className='tw-h-20 tw-w-20 tw-rounded-full'
|
||||
className='tw:h-20 tw:w-20 tw:rounded-full'
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className='tw-h-20 tw-w-20'>
|
||||
<img src={UserSVG} className='tw-rounded-full'></img>
|
||||
<div className='tw:h-20 tw:w-20'>
|
||||
<img src={UserSVG} className='tw:rounded-full'></img>
|
||||
</div>
|
||||
)}
|
||||
</label>
|
||||
) : (
|
||||
<div className='tw-w-20 tw-flex tw-items-center tw-justify-center'>
|
||||
<span className='tw-loading tw-loading-spinner'></span>
|
||||
<div className='tw:w-20 tw:flex tw:items-center tw:justify-center'>
|
||||
<span className='tw:loading tw:loading-spinner'></span>
|
||||
</div>
|
||||
)}
|
||||
<DialogModal
|
||||
@ -203,7 +203,7 @@ export const AvatarWidget: React.FC<AvatarWidgetProps> = ({ avatar, setAvatar })
|
||||
<img src={image} ref={imgRef} onLoad={onImageLoad} />
|
||||
</ReactCrop>
|
||||
<button
|
||||
className={'tw-btn tw-btn-primary'}
|
||||
className={'tw:btn tw:btn-primary'}
|
||||
onClick={() => {
|
||||
setCropping(true)
|
||||
setCropModalOpen(false)
|
||||
|
||||
@ -38,7 +38,7 @@ export const ColorPicker = ({ color, onChange, className }) => {
|
||||
<div className='swatch' style={{ backgroundColor: color }} onClick={() => toggle(true)} />
|
||||
|
||||
{isOpen && (
|
||||
<div className='popover tw-z-[10000]' ref={popover}>
|
||||
<div className='popover tw:z-10000' ref={popover}>
|
||||
<HexColorPicker color={color} onChange={onChange} onClick={() => toggle(false)} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -12,11 +12,11 @@ export const ContactInfoForm = ({
|
||||
setState: React.Dispatch<React.SetStateAction<any>>
|
||||
}) => {
|
||||
return (
|
||||
<div className='tw-mt-4 tw-space-y-4'>
|
||||
<div className='tw:mt-4 tw:space-y-4'>
|
||||
<div>
|
||||
<label
|
||||
htmlFor='email'
|
||||
className='tw-block tw-text-sm tw-font-medium tw-text-gray-500 tw-mb-1'
|
||||
className='tw:block tw:text-sm tw:font-medium tw:text-gray-500 tw:mb-1'
|
||||
>
|
||||
Email-Adresse (Kontakt):
|
||||
</label>
|
||||
@ -37,7 +37,7 @@ export const ContactInfoForm = ({
|
||||
<div>
|
||||
<label
|
||||
htmlFor='telephone'
|
||||
className='tw-block tw-text-sm tw-font-medium tw-text-gray-500 tw-mb-1'
|
||||
className='tw:block tw:text-sm tw:font-medium tw:text-gray-500 tw:mb-1'
|
||||
>
|
||||
Telefonnummer (Kontakt):
|
||||
</label>
|
||||
|
||||
@ -24,33 +24,33 @@ export const ContactInfoView = ({ item, heading }: { item: Item; heading: string
|
||||
}, [item, items])
|
||||
|
||||
return (
|
||||
<div className='tw-bg-base-200 tw-mb-6 tw-mt-6 tw-p-6'>
|
||||
<h2 className='tw-text-lg tw-font-semibold'>{heading}</h2>
|
||||
<div className='tw-mt-4 tw-flex tw-items-center'>
|
||||
<div className='tw:bg-base-200 tw:mb-6 tw:mt-6 tw:p-6'>
|
||||
<h2 className='tw:text-lg tw:font-semibold'>{heading}</h2>
|
||||
<div className='tw:mt-4 tw:flex tw:items-center'>
|
||||
{profileOwner?.image && (
|
||||
<ConditionalLink url={'/item/' + profileOwner?.id}>
|
||||
<div className='tw-mr-5 tw-flex tw-items-center tw-justify-center'>
|
||||
<div className='tw-avatar'>
|
||||
<div className='tw-w-20 tw-h-20 tw-bg-gray-200 rounded-full tw-flex tw-items-center tw-justify-center overflow-hidden'>
|
||||
<div className='tw:mr-5 tw:flex tw:items-center tw:justify-center'>
|
||||
<div className='tw:avatar'>
|
||||
<div className='tw:w-20 tw:h-20 tw:bg-gray-200 rounded-full tw:flex tw:items-center tw:justify-center overflow-hidden'>
|
||||
<img
|
||||
src={appState.assetsApi.url + profileOwner?.image}
|
||||
alt={profileOwner?.name}
|
||||
className='tw-w-full tw-h-full tw-object-cover'
|
||||
className='tw:w-full tw:h-full tw:object-cover'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ConditionalLink>
|
||||
)}
|
||||
<div className='tw-text-sm tw-flex-grow'>
|
||||
<p className='tw-font-semibold'>{profileOwner?.name}</p>
|
||||
<div className='tw:text-sm tw:grow'>
|
||||
<p className='tw:font-semibold'>{profileOwner?.name}</p>
|
||||
{item.contact && (
|
||||
<p>
|
||||
<a
|
||||
href={`mailto:${item.contact}`}
|
||||
className='tw-mt-2 tw-text-green-500 tw-inline-flex tw-items-center'
|
||||
className='tw:mt-2 tw:text-green-500 tw:inline-flex tw:items-center'
|
||||
>
|
||||
<EnvelopeIcon className='tw-w-4 tw-h-4 tw-mr-1' />
|
||||
<EnvelopeIcon className='tw:w-4 tw:h-4 tw:mr-1' />
|
||||
{item.contact}
|
||||
</a>
|
||||
</p>
|
||||
@ -59,9 +59,9 @@ export const ContactInfoView = ({ item, heading }: { item: Item; heading: string
|
||||
<p>
|
||||
<a
|
||||
href={`tel:${item.telephone}`}
|
||||
className='tw-mt-2 tw-text-green-500 tw-inline-flex tw-items-center tw-whitespace-nowrap'
|
||||
className='tw:mt-2 tw:text-green-500 tw:inline-flex tw:items-center tw:whitespace-nowrap'
|
||||
>
|
||||
<PhoneIcon className='tw-w-4 tw-h-4 tw-mr-1' />
|
||||
<PhoneIcon className='tw:w-4 tw:h-4 tw:mr-1' />
|
||||
{item.telephone}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@ -12,11 +12,11 @@ export const CrowdfundingForm = ({
|
||||
setState: React.Dispatch<React.SetStateAction<any>>
|
||||
}) => {
|
||||
return (
|
||||
<div className='tw-mt-4 tw-space-y-4'>
|
||||
<div className='tw:mt-4 tw:space-y-4'>
|
||||
<div>
|
||||
<label
|
||||
htmlFor='OpenCollectiveSlug'
|
||||
className='tw-block tw-text-sm tw-font-medium tw-text-gray-500 tw-mb-1'
|
||||
className='tw:block tw:text-sm tw:font-medium tw:text-gray-500 tw:mb-1'
|
||||
>
|
||||
Open Collective Slug:
|
||||
</label>
|
||||
|
||||
@ -121,18 +121,18 @@ export const CrowdfundingView = ({ item }: { item: Item }) => {
|
||||
|
||||
if (loading)
|
||||
return (
|
||||
<div className='tw-flex tw-justify-center'>
|
||||
<span className='tw-loading tw-loading-spinner tw-loading-lg tw-text-neutral-content'></span>
|
||||
<div className='tw:flex tw:justify-center'>
|
||||
<span className='tw:loading tw:loading-spinner tw:loading-lg tw:text-neutral-content'></span>
|
||||
</div>
|
||||
)
|
||||
|
||||
if (error) {
|
||||
return <p className='tw-text-center tw-text-lg tw-text-red-500'>Error: {error}</p>
|
||||
return <p className='tw:text-center tw:text-lg tw:text-red-500'>Error: {error}</p>
|
||||
}
|
||||
|
||||
if (!data?.account) {
|
||||
return (
|
||||
<p className='tw-text-center tw-text-lg tw-text-red-500'>
|
||||
<p className='tw:text-center tw:text-lg tw:text-red-500'>
|
||||
No data available for this account.
|
||||
</p>
|
||||
)
|
||||
@ -144,46 +144,46 @@ export const CrowdfundingView = ({ item }: { item: Item }) => {
|
||||
const currentBalance = balanceValueInCents
|
||||
|
||||
return (
|
||||
<div className='tw-mx-6 tw-mb-6'>
|
||||
<div className='tw-card tw-bg-base-200 tw-w-fit tw-max-w-full tw-shadow'>
|
||||
<div className='tw-stats tw-bg-base-200 tw-stats-horizontal tw-rounded-b-none'>
|
||||
<div className='tw-stat tw-p-3'>
|
||||
<div className='tw-stat-title'>Current Balance</div>
|
||||
<div className='tw-stat-value tw-text-xl lg:tw-text-3xl'>
|
||||
<div className='tw:mx-6 tw:mb-6'>
|
||||
<div className='tw:card tw:bg-base-200 tw:w-fit tw:max-w-full tw:shadow'>
|
||||
<div className='tw:stats tw:bg-base-200 tw:stats-horizontal tw:rounded-b-none'>
|
||||
<div className='tw:stat tw:p-3'>
|
||||
<div className='tw:stat-title'>Current Balance</div>
|
||||
<div className='tw:stat-value tw:text-xl lg:tw:text-3xl'>
|
||||
{formatCurrency(currentBalance, currency)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='tw-stat tw-p-3'>
|
||||
<div className='tw-stat-title'>Received</div>
|
||||
<div className='tw-stat-value tw-text-green-500 tw-text-xl lg:tw-text-3xl'>
|
||||
<div className='tw:stat tw:p-3'>
|
||||
<div className='tw:stat-title'>Received</div>
|
||||
<div className='tw:stat-value tw:text-green-500 tw:text-xl lg:tw:text-3xl'>
|
||||
{formatCurrency(stats.totalAmountReceived.valueInCents, currency)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='tw-stat tw-p-3'>
|
||||
<div className='tw-stat-title'>Spent</div>
|
||||
<div className='tw-stat-value tw-text-red-500 tw-text-xl lg:tw-text-3xl'>
|
||||
<div className='tw:stat tw:p-3'>
|
||||
<div className='tw:stat-title'>Spent</div>
|
||||
<div className='tw:stat-value tw:text-red-500 tw:text-xl lg:tw:text-3xl'>
|
||||
{formatCurrency(stats.totalAmountReceived.valueInCents - currentBalance, currency)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr></hr>
|
||||
<div className='tw-m-4 tw-items-center'>
|
||||
<hr className='tw:border-1 tw:border-current/10 tw:border-dashed'></hr>
|
||||
<div className='tw:m-4 tw:items-center'>
|
||||
<a href={`https://opencollective.com/${slug}/donate`} target='_blank' rel='noreferrer'>
|
||||
<button className='tw-btn tw-btn-sm tw-btn-primary tw-float-right tw-ml-4'>
|
||||
<button className='tw:btn tw:btn-sm tw:btn-primary tw:float-right tw:ml-4'>
|
||||
Donate
|
||||
</button>
|
||||
</a>
|
||||
<div className='tw-flex-1 tw-mr-4'>
|
||||
<div className='tw:flex-1 tw:mr-4'>
|
||||
Support{' '}
|
||||
<a
|
||||
className='tw-font-bold'
|
||||
className='tw:font-bold'
|
||||
href={`https://opencollective.com/${slug}`}
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
>
|
||||
{data.account.name}
|
||||
</a>{' '}
|
||||
on <span className='tw-font-bold'>Open Collective</span>
|
||||
on <span className='tw:font-bold'>Open Collective</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -10,50 +10,54 @@ import { ColorPicker } from './ColorPicker'
|
||||
|
||||
export const FormHeader = ({ item, state, setState }) => {
|
||||
return (
|
||||
<div className='tw-flex'>
|
||||
<AvatarWidget
|
||||
avatar={state.image}
|
||||
setAvatar={(i) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
image: i,
|
||||
}))
|
||||
}
|
||||
/>
|
||||
<ColorPicker
|
||||
color={state.color}
|
||||
onChange={(c) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
color: c,
|
||||
}))
|
||||
}
|
||||
className={'-tw-left-6 tw-top-14 -tw-mr-6'}
|
||||
/>
|
||||
<div className='tw-grow tw-mr-4'>
|
||||
<TextInput
|
||||
placeholder='Name'
|
||||
defaultValue={item?.name ? item.name : ''}
|
||||
updateFormValue={(v) =>
|
||||
<div className='tw:flex-none'>
|
||||
<div className='tw:flex'>
|
||||
<AvatarWidget
|
||||
avatar={state.image}
|
||||
setAvatar={(i) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
name: v,
|
||||
image: i,
|
||||
}))
|
||||
}
|
||||
containerStyle='tw-grow tw-input-md'
|
||||
/>
|
||||
<TextInput
|
||||
placeholder='Subtitle'
|
||||
required={false}
|
||||
defaultValue={item?.subname ? item.subname : ''}
|
||||
updateFormValue={(v) =>
|
||||
<ColorPicker
|
||||
color={state.color}
|
||||
onChange={(c) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
subname: v,
|
||||
color: c,
|
||||
}))
|
||||
}
|
||||
containerStyle='tw-grow tw-input-sm tw-px-4 tw-mt-1'
|
||||
className={'tw:-left-6 tw:top-14 tw:-mr-6'}
|
||||
/>
|
||||
<div className='tw:grow tw:mr-4 tw:pt-1'>
|
||||
<TextInput
|
||||
placeholder='Name'
|
||||
defaultValue={item?.name ? item.name : ''}
|
||||
updateFormValue={(v) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
name: v,
|
||||
}))
|
||||
}
|
||||
containerStyle='tw:grow tw:px-4'
|
||||
inputStyle='tw:input-md'
|
||||
/>
|
||||
<TextInput
|
||||
placeholder='Subtitle'
|
||||
required={false}
|
||||
defaultValue={item?.subname ? item.subname : ''}
|
||||
updateFormValue={(v) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
subname: v,
|
||||
}))
|
||||
}
|
||||
containerStyle='tw:grow tw:px-4 tw:mt-1'
|
||||
inputStyle='tw:input-sm'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -21,7 +21,7 @@ export const GalleryView = ({ item }: { item: Item }) => {
|
||||
if (!images) throw new Error('GalleryView: images is undefined')
|
||||
|
||||
return (
|
||||
<div className='tw-mx-6 tw-mb-6'>
|
||||
<div className='tw:mx-6 tw:mb-6'>
|
||||
<RowsPhotoAlbum
|
||||
photos={images}
|
||||
targetRowHeight={150}
|
||||
|
||||
@ -11,18 +11,18 @@ export const GroupSubHeaderView = ({
|
||||
shareBaseUrl: string
|
||||
platforms?: string[]
|
||||
}) => (
|
||||
<div className='tw-px-6'>
|
||||
<div className='tw-float-left tw-mt-2 tw-mb-4 tw-flex tw-items-center'>
|
||||
<div className='tw:px-6'>
|
||||
<div className='tw:float-left tw:mt-2 tw:mb-4 tw:flex tw:items-center'>
|
||||
{item.status && (
|
||||
<div className='tw-mt-1.5'>
|
||||
<span className='tw-text-sm tw-text-current tw-bg-base-300 tw-rounded tw-py-0.5 tw-px-2 tw-inline-flex tw-items-center tw-mr-2'>
|
||||
<div className='tw:mt-1.5'>
|
||||
<span className='tw:text-sm tw:text-current tw:bg-base-300 tw:rounded tw:py-0.5 tw:px-2 tw:inline-flex tw:items-center tw:mr-2'>
|
||||
{item.status}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{item.group_type && (
|
||||
<div className='tw-mt-1.5'>
|
||||
<span className='tw-text-sm tw-text-current tw-bg-base-300 tw-rounded tw-py-1 tw-px-2'>
|
||||
<div className='tw:mt-1.5'>
|
||||
<span className='tw:text-sm tw:text-current tw:bg-base-300 tw:rounded tw:py-1 tw:px-2'>
|
||||
{item.group_type}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@ -51,11 +51,11 @@ export const GroupSubheaderForm = ({
|
||||
}, [state.group_type, groupTypes])
|
||||
|
||||
return (
|
||||
<div className='tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6'>
|
||||
<div className='tw:grid tw:grid-cols-1 tw:md:grid-cols-2 tw:gap-6'>
|
||||
<div>
|
||||
<label
|
||||
htmlFor='status'
|
||||
className='tw-block tw-text-sm tw-font-medium tw-text-gray-500 tw-mb-1'
|
||||
className='tw:block tw:text-sm tw:font-medium tw:text-gray-500 tw:mb-1'
|
||||
>
|
||||
Gruppenstatus:
|
||||
</label>
|
||||
@ -74,7 +74,7 @@ export const GroupSubheaderForm = ({
|
||||
<div>
|
||||
<label
|
||||
htmlFor='groupType'
|
||||
className='tw-block tw-text-sm tw-font-medium tw-text-gray-500 tw-mb-1'
|
||||
className='tw:block tw:text-sm tw:font-medium tw:text-gray-500 tw:mb-1'
|
||||
>
|
||||
Gruppenart:
|
||||
</label>
|
||||
|
||||
@ -33,47 +33,47 @@ export function LinkedItemsHeaderView({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='tw-flex tw-flex-row'>
|
||||
<div className={'tw-grow tw-max-w-[calc(100%-60px)] }'}>
|
||||
<div className='tw:flex tw:flex-row'>
|
||||
<div className={'tw:grow tw:max-w-[calc(100%-60px)] }'}>
|
||||
<div className='flex items-center'>
|
||||
{avatar && (
|
||||
<img
|
||||
className={'tw-w-10 tw-inline tw-rounded-full'}
|
||||
className={'tw:w-10 tw:inline tw:rounded-full'}
|
||||
src={avatar}
|
||||
alt={item.name + ' logo'}
|
||||
/>
|
||||
)}
|
||||
<div className={`${avatar ? 'tw-ml-2' : ''} tw-overflow-hidden`}>
|
||||
<div className={'tw-text-xl tw-font-semibold tw-truncate'}>{title}</div>
|
||||
<div className={`${avatar ? 'tw:ml-2' : ''} tw:overflow-hidden`}>
|
||||
<div className={'tw:text-xl tw:font-semibold tw:truncate'}>{title}</div>
|
||||
{subtitle && (
|
||||
<div className='tw-text-xs tw-truncate tw-text-gray-500 '>{subtitle}</div>
|
||||
<div className='tw:text-xs tw:truncate tw:text-gray-500 '>{subtitle}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='tw-col-span-1' onClick={(e) => e.stopPropagation()}>
|
||||
<div className='tw:col-span-1' onClick={(e) => e.stopPropagation()}>
|
||||
{unlinkPermission && (
|
||||
<div className='tw-dropdown tw-dropdown-bottom'>
|
||||
<div className='tw:dropdown tw:dropdown-bottom'>
|
||||
<label
|
||||
tabIndex={0}
|
||||
className=' tw-btn tw-m-1 tw-leading-3 tw-border-none tw-min-h-0 tw-h-6'
|
||||
className=' tw:btn tw:m-1 tw:leading-3 tw:border-none tw:min-h-0 tw:h-6'
|
||||
>
|
||||
<EllipsisVerticalIcon className='tw-h-5 tw-w-5' />
|
||||
<EllipsisVerticalIcon className='tw:h-5 tw:w-5' />
|
||||
</label>
|
||||
<ul
|
||||
tabIndex={0}
|
||||
className='tw-dropdown-content tw-menu tw-p-2 tw-shadow tw-bg-base-100 tw-rounded-box tw-z-1000'
|
||||
className='tw:dropdown-content tw:menu tw:p-2 tw:shadow tw:bg-base-100 tw:rounded-box tw:z-1000'
|
||||
>
|
||||
{true && (
|
||||
<li>
|
||||
<a
|
||||
className='tw-cursor-pointer !tw-text-error'
|
||||
className='tw:cursor-pointer tw:text-error!'
|
||||
onClick={() => unlinkCallback(item.id)}
|
||||
>
|
||||
{loading ? (
|
||||
<span className='tw-loading tw-loading-spinner tw-loading-sm'></span>
|
||||
<span className='tw:loading tw:loading-spinner tw:loading-sm'></span>
|
||||
) : (
|
||||
<LinkSlashIcon className='tw-h-5 tw-w-5 tw-stroke-[3]' />
|
||||
<LinkSlashIcon className='tw:h-5 tw:w-5 tw:stroke-3' />
|
||||
)}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@ -8,16 +8,16 @@ export const MarkdownHint = () => {
|
||||
<div
|
||||
onClick={() => setExpended(true)}
|
||||
title='Markdown is supported'
|
||||
className='flex tw-flex-row tw-text-gray-400 tw-cursor-pointer tw-items-center'
|
||||
className='flex tw:flex-row tw:text-gray-400 tw:cursor-pointer tw:items-center'
|
||||
>
|
||||
<img src={MarkdownSVG} alt='Markdown' className='octicon octicon-markdown tw-gray-400' />
|
||||
<img src={MarkdownSVG} alt='Markdown' className='octicon octicon-markdown tw:gray-400' />
|
||||
{expended && (
|
||||
<a
|
||||
href='https://www.markdownguide.org/cheat-sheet/#basic-syntax'
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
>
|
||||
<span className='Button-label tw-ml-1'>Markdown is support</span>{' '}
|
||||
<span className='Button-label tw:ml-1'>Markdown is support</span>{' '}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -21,16 +21,16 @@ export function PlusButton({
|
||||
return (
|
||||
<>
|
||||
{hasUserPermission(collection, 'create', undefined, layer) && (
|
||||
<div className='tw-dropdown tw-dropdown-top tw-dropdown-end tw-dropdown-hover tw-z-3000 tw-absolute tw-right-4 tw-bottom-4'>
|
||||
<div className='tw:dropdown tw:dropdown-top tw:dropdown-end tw:dropdown-hover tw:z-3000 tw:absolute tw:right-4 tw:bottom-4'>
|
||||
<button
|
||||
tabIndex={0}
|
||||
className='tw-z-500 tw-btn tw-btn-circle tw-shadow'
|
||||
className='tw:z-500 tw:btn tw:btn-circle tw:shadow'
|
||||
onClick={() => {
|
||||
triggerAction()
|
||||
}}
|
||||
style={{ backgroundColor: color, color: '#fff' }}
|
||||
>
|
||||
<PlusIcon className='tw-w-5 tw-h-5 tw-stroke-[2.5]' />
|
||||
<PlusIcon className='tw:w-5 tw:h-5 tw:stroke-[2.5]' />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -4,7 +4,7 @@ import type { Item } from '#types/Item'
|
||||
|
||||
export const ProfileStartEndView = ({ item }: { item: Item }) => {
|
||||
return (
|
||||
<div className='tw-mt-2 tw-px-6 tw-max-w-xs'>
|
||||
<div className='tw:mt-2 tw:px-6 tw:max-w-xs'>
|
||||
<StartEndView item={item}></StartEndView>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -37,11 +37,11 @@ export const ProfileTextForm = ({
|
||||
}, [dataField])
|
||||
|
||||
return (
|
||||
<div className='tw-h-full tw-flex tw-flex-col tw-mt-4'>
|
||||
<div className='tw-flex tw-justify-between tw-items-center'>
|
||||
<div className='tw:h-full tw:flex tw:flex-col tw:mt-4'>
|
||||
<div className='tw:flex tw:justify-between tw:items-center'>
|
||||
<label
|
||||
htmlFor='nextAppointment'
|
||||
className='tw-block tw-text-sm tw-font-medium tw-text-gray-500 tw-mb-1'
|
||||
className='tw:block tw:text-sm tw:font-medium tw:text-gray-500 tw:mb-1'
|
||||
>
|
||||
{heading || 'Text'}:
|
||||
</label>
|
||||
@ -57,9 +57,9 @@ export const ProfileTextForm = ({
|
||||
[field]: v,
|
||||
}))
|
||||
}
|
||||
labelStyle={hideInputLabel ? 'tw-hidden' : ''}
|
||||
containerStyle={size === 'full' ? 'tw-grow tw-h-full' : ''}
|
||||
inputStyle={size === 'full' ? 'tw-h-full' : 'tw-h-24'}
|
||||
labelStyle={hideInputLabel ? 'tw:hidden' : ''}
|
||||
containerStyle={size === 'full' ? 'tw:grow tw:h-full' : ''}
|
||||
inputStyle={size === 'full' ? 'tw:h-full' : 'tw:h-24'}
|
||||
required={required}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -20,11 +20,11 @@ export const ProfileTextView = ({
|
||||
const parsedText = typeof text !== 'string' ? '' : text
|
||||
|
||||
return (
|
||||
<div className='tw-my-10 tw-mt-2 tw-px-6'>
|
||||
<div className='tw:my-10 tw:mt-2 tw:px-6'>
|
||||
{!(text === '' && hideWhenEmpty) && (
|
||||
<h2 className='tw-text-lg tw-font-semibold'>{heading}</h2>
|
||||
<h2 className='tw:text-lg tw:font-semibold'>{heading}</h2>
|
||||
)}
|
||||
<div className='tw-mt-2 tw-text-sm'>
|
||||
<div className='tw:mt-2 tw:text-sm'>
|
||||
<TextView itemId={item.id} rawText={parsedText} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
// eslint-disable-next-line react/prop-types
|
||||
const RelationCard = ({ title, description, imageSrc }) => (
|
||||
<div className={`tw-mb-6 ${imageSrc ? 'md:tw-flex md:tw-space-x-4' : ''}`}>
|
||||
<div className={`tw:mb-6 ${imageSrc ? 'tw:md:flex tw:md:space-x-4' : ''}`}>
|
||||
{imageSrc && (
|
||||
<div className='md:tw-w-1/2 tw-mb-4 md:tw-mb-0'>
|
||||
<img src={imageSrc} alt={title} className='tw-w-full tw-h-32 tw-object-cover' />
|
||||
<div className='tw:md:w-1/2 tw:mb-4 tw:md:mb-0'>
|
||||
<img src={imageSrc} alt={title} className='tw:w-full tw:h-32 tw:object-cover' />
|
||||
</div>
|
||||
)}
|
||||
<div className={imageSrc ? 'md:tw-w-1/2' : 'tw-w-full'}>
|
||||
<h3 className='tw-text-lg tw-font-semibold'>{title}</h3>
|
||||
<p className='tw-mt-2 tw-text-sm tw-text-gray-600'>{description}</p>
|
||||
<div className={imageSrc ? 'tw:md:w-1/2' : 'tw:w-full'}>
|
||||
<h3 className='tw:text-lg tw:font-semibold'>{title}</h3>
|
||||
<p className='tw:mt-2 tw:text-sm tw:text-gray-600'>{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -27,7 +27,7 @@ const SocialShareBar = ({
|
||||
})
|
||||
}
|
||||
return (
|
||||
<div className='tw-flex tw-place-content-end tw-justify-end tw-space-x-2 tw-grow tw-min-w-fit tw-pl-2'>
|
||||
<div className='tw:flex tw:place-content-end tw:justify-end tw:space-x-2 tw:grow tw:min-w-fit tw:pl-2'>
|
||||
{platforms.map((platform) => (
|
||||
<SocialShareButton key={platform} platform={platform} url={url} title={title} />
|
||||
))}
|
||||
@ -36,7 +36,7 @@ const SocialShareBar = ({
|
||||
href={`mailto:?subject=${title}&body=${url}`}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='tw-w-8 tw-h-8 tw-mt-2 tw-rounded-full tw-flex tw-items-center tw-justify-center tw-text-white hover:tw-cursor-pointer'
|
||||
className='tw:w-8 tw:h-8 tw:mt-2 tw:rounded-full tw:flex tw:items-center tw:justify-center tw:text-white tw:hover:cursor-pointer'
|
||||
style={{
|
||||
color: 'white',
|
||||
backgroundColor: '#444',
|
||||
@ -44,13 +44,13 @@ const SocialShareBar = ({
|
||||
onClick={() => copyLink()}
|
||||
title='share link via email'
|
||||
>
|
||||
<img src={ChevronSVG} alt='\/' className='tw-h-4 tw-w-4' />
|
||||
<img src={ChevronSVG} alt='\/' className='tw:h-4 tw:w-4' />
|
||||
</a>
|
||||
)}
|
||||
{platforms.includes('clipboard') && (
|
||||
<div
|
||||
rel='noopener noreferrer'
|
||||
className='tw-w-8 tw-h-8 tw-mt-2 tw-rounded-full tw-flex tw-items-center tw-justify-center tw-text-white hover:tw-cursor-pointer'
|
||||
className='tw:w-8 tw:h-8 tw:mt-2 tw:rounded-full tw:flex tw:items-center tw:justify-center tw:text-white tw:hover:cursor-pointer'
|
||||
style={{
|
||||
color: 'white',
|
||||
backgroundColor: '#888',
|
||||
@ -58,7 +58,7 @@ const SocialShareBar = ({
|
||||
onClick={() => copyLink()}
|
||||
title='copy Link'
|
||||
>
|
||||
<img src={ClipboardSVG} className='tw-w-5' />
|
||||
<img src={ClipboardSVG} className='tw:w-5' />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -71,14 +71,14 @@ const SocialShareButton = ({
|
||||
href={finalShareUrl}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='tw-w-8 tw-h-8 tw-mt-2 tw-rounded-full tw-flex tw-items-center tw-justify-center tw-text-white'
|
||||
className='tw:w-8 tw:h-8 tw:mt-2 tw:rounded-full tw:flex tw:items-center tw:justify-center tw:text-white'
|
||||
style={{
|
||||
color: 'white',
|
||||
backgroundColor: bgColor,
|
||||
}}
|
||||
title={`share link on ${platform}`}
|
||||
>
|
||||
{cloneElement(icon, { className: 'tw-w-4 tw-h-4 tw-fill-current' })}
|
||||
{cloneElement(icon, { className: 'tw:w-4 tw:h-4 tw:fill-current' })}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
@ -95,7 +95,7 @@ export const TagsWidget = ({ placeholder, containerStyle, defaultTags, onUpdate
|
||||
onKeyDown,
|
||||
onKeyUp,
|
||||
onChange,
|
||||
className: 'tw-bg-transparent tw-w-fit tw-mt-5 tw-h-fit',
|
||||
className: 'tw:bg-transparent tw:w-fit tw:mt-5 tw:h-fit',
|
||||
}
|
||||
|
||||
/* eslint-disable react/prop-types */
|
||||
@ -107,18 +107,18 @@ export const TagsWidget = ({ placeholder, containerStyle, defaultTags, onUpdate
|
||||
setFocusInput(false)
|
||||
}, 200)
|
||||
}}
|
||||
className={`tw-input tw-input-bordered tw-cursor-text ${containerStyle}`}
|
||||
className={`tw:textarea tw:cursor-text ${containerStyle}`}
|
||||
>
|
||||
<div className='tw-flex tw-flex-wrap tw-h-fit'>
|
||||
<div className='tw:flex tw:flex-wrap tw:h-fit'>
|
||||
{defaultTags.map((tag) => (
|
||||
<div
|
||||
key={tag.name}
|
||||
className='tw-rounded-2xl tw-text-white tw-p-2 tw-px-4 tw-shadow-xl tw-card tw-mt-3 tw-mr-4'
|
||||
className='tw:rounded-2xl tw:text-white tw:p-2 tw:px-4 tw:shadow-xl tw:card tw:mt-3 tw:mr-4'
|
||||
style={{ backgroundColor: tag.color ? tag.color : '#666' }}
|
||||
>
|
||||
<div className='tw-card-actions tw-justify-end'>
|
||||
<div className='tw:card-actions tw:justify-end'>
|
||||
<label
|
||||
className='tw-btn tw-btn-xs tw-btn-circle tw-absolute tw--right-2 tw--top-2 tw-bg-white tw-text-gray-600'
|
||||
className='tw:btn tw:btn-xs tw:btn-circle tw:absolute tw:-right-2 tw:-top-2 tw:bg-white tw:text-gray-600'
|
||||
onClick={() => deleteTag(tag)}
|
||||
>
|
||||
✕
|
||||
|
||||
@ -29,7 +29,7 @@ export const FlexForm = ({
|
||||
item: Item
|
||||
}) => {
|
||||
return (
|
||||
<div className='tw-mt-6 tw-flex tw-flex-col tw-h-full'>
|
||||
<div className='tw:mt-6 tw:flex tw:flex-col tw:h-full'>
|
||||
{item.layer?.itemType.profileTemplate.map((templateItem) => {
|
||||
const TemplateComponent = componentMap[templateItem.collection]
|
||||
return TemplateComponent ? (
|
||||
@ -41,7 +41,9 @@ export const FlexForm = ({
|
||||
{...templateItem.item}
|
||||
/>
|
||||
) : (
|
||||
<div key={templateItem.id}>Component not found</div>
|
||||
<div className='tw:mt-2' key={templateItem.id}>
|
||||
{templateItem.collection} form not found
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
@ -21,10 +21,8 @@ const componentMap = {
|
||||
}
|
||||
|
||||
export const FlexView = ({ item }: { item: Item }) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(item)
|
||||
return (
|
||||
<div className='tw-h-full tw-overflow-y-auto fade'>
|
||||
<div className='tw:h-full tw:overflow-y-auto fade'>
|
||||
{item.layer?.itemType.profileTemplate.map(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(templateItem: { collection: string | number; id: Key | null | undefined; item: any }) => {
|
||||
@ -32,7 +30,9 @@ export const FlexView = ({ item }: { item: Item }) => {
|
||||
return TemplateComponent ? (
|
||||
<TemplateComponent key={templateItem.id} item={item} {...templateItem.item} />
|
||||
) : (
|
||||
<div key={templateItem.id}>Component not found</div>
|
||||
<div className='tw:mx-6 tw:mb-6' key={templateItem.id}>
|
||||
{templateItem.collection} view not found
|
||||
</div>
|
||||
)
|
||||
},
|
||||
)}
|
||||
|
||||
@ -17,14 +17,14 @@ export const OnepagerForm = ({
|
||||
item: Item
|
||||
}) => {
|
||||
return (
|
||||
<div className='tw-space-y-6 tw-mt-6'>
|
||||
<div className='tw:space-y-6 tw:mt-6'>
|
||||
<GroupSubheaderForm state={state} setState={setState} item={item}></GroupSubheaderForm>
|
||||
<ContactInfoForm state={state} setState={setState}></ContactInfoForm>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor='description'
|
||||
className='tw-block tw-text-sm tw-font-medium tw-text-gray-500 tw-mb-1'
|
||||
className='tw:block tw:text-sm tw:font-medium tw:text-gray-500 tw:mb-1'
|
||||
>
|
||||
Gruppenbeschreibung:
|
||||
</label>
|
||||
@ -37,7 +37,7 @@ export const OnepagerForm = ({
|
||||
text: v,
|
||||
}))
|
||||
}
|
||||
inputStyle='tw-h-48'
|
||||
inputStyle='tw:h-48'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -7,29 +7,29 @@ import type { Item } from '#types/Item'
|
||||
|
||||
export const OnepagerView = ({ item }: { item: Item }) => {
|
||||
return (
|
||||
<div className='tw-h-full tw-overflow-y-auto fade'>
|
||||
<div className='tw:h-full tw:overflow-y-auto fade'>
|
||||
<GroupSubHeaderView
|
||||
item={item}
|
||||
shareBaseUrl={`https://www.wuerdekompass.org/aktivitaeten/gruppensuche/#/gruppe/${item.slug}`}
|
||||
/>
|
||||
{item.user_created?.first_name && <ContactInfoView heading='Du hast Fragen?' item={item} />}
|
||||
{/* Description Section */}
|
||||
<div className='tw-my-10 tw-mt-2 tw-px-6 tw-text-sm '>
|
||||
<div className='tw:my-10 tw:mt-2 tw:px-6 tw:text-sm '>
|
||||
<TextView itemId={item.id} rawText={item.text ?? 'Keine Beschreibung vorhanden'} />
|
||||
</div>
|
||||
{/* Next Appointment Section */}
|
||||
{item.next_appointment && (
|
||||
<div className='tw-my-10 tw-px-6'>
|
||||
<h2 className='tw-text-lg tw-font-semibold'>Nächste Termine</h2>
|
||||
<div className='tw-mt-2 tw-text-sm'>
|
||||
<div className='tw:my-10 tw:px-6'>
|
||||
<h2 className='tw:text-lg tw:font-semibold'>Nächste Termine</h2>
|
||||
<div className='tw:mt-2 tw:text-sm'>
|
||||
<TextView itemId={item.id} rawText={item.next_appointment} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
;{/* Relations Section */}
|
||||
{/* {d.relations && ( */}
|
||||
{/* <div className="tw-my-10 tw-px-6"> */}
|
||||
{/* <h2 className="tw-text-lg tw-font-semibold tw-mb-4">Projekte</h2> */}
|
||||
{/* <div className="tw:my-10 tw:px-6"> */}
|
||||
{/* <h2 className="tw:text-lg tw:font-semibold tw:mb-4">Projekte</h2> */}
|
||||
{/* {d.relations.map((project, index) => ( */}
|
||||
{/* <RelationCard */}
|
||||
{/* key={index} */}
|
||||
|
||||
@ -17,8 +17,8 @@ export const SimpleForm = ({ state, setState }) => {
|
||||
text: v,
|
||||
}))
|
||||
}
|
||||
containerStyle='tw-mt-8 tw-h-full'
|
||||
inputStyle='tw-h-full'
|
||||
containerStyle='tw:mt-8 tw:h-full'
|
||||
inputStyle='tw:h-full'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import type { Item } from '#types/Item'
|
||||
|
||||
export const SimpleView = ({ item }: { item: Item }) => {
|
||||
return (
|
||||
<div className='tw-mt-8 tw-h-full tw-overflow-y-auto fade tw-px-6'>
|
||||
<div className='tw:mt-8 tw:h-full tw:overflow-y-auto fade tw:px-6'>
|
||||
<TextView text={item.text} itemId={item.id} />
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -53,55 +53,55 @@ export const TabsForm = ({
|
||||
}, [location.search])
|
||||
|
||||
return (
|
||||
<div role='tablist' className='tw-tabs tw-tabs-lifted tw-mt-3'>
|
||||
<input
|
||||
type='radio'
|
||||
name='my_tabs_2'
|
||||
role='tab'
|
||||
className={'tw-tab [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]'}
|
||||
aria-label='Info'
|
||||
checked={activeTab === 1 && true}
|
||||
onChange={() => updateActiveTab(1)}
|
||||
/>
|
||||
<div
|
||||
role='tabpanel'
|
||||
className='tw-tab-content tw-bg-base-100 tw-border-[var(--fallback-bc,oklch(var(--bc)/0.2))] tw-rounded-box tw-h-[calc(100dvh-332px)] tw-min-h-56 tw-border-none'
|
||||
>
|
||||
<div className='tw:grow'>
|
||||
<div role='tablist' className='tw:tabs tw:h-full tw:tabs-lift tw:mt-3'>
|
||||
<input
|
||||
type='radio'
|
||||
name='my_tabs_2'
|
||||
role='tab'
|
||||
className={'tw:tab '}
|
||||
aria-label='Info'
|
||||
checked={activeTab === 1 && true}
|
||||
onChange={() => updateActiveTab(1)}
|
||||
/>
|
||||
<div
|
||||
className={`tw-flex tw-flex-col tw-h-full ${item.layer.itemType.show_start_end_input && 'tw-pt-4'}`}
|
||||
role='tabpanel'
|
||||
className='tw:tab-content tw:bg-base-100 tw:border-(--fallback-bc,oklch(var(--bc)/0.2)) tw:rounded-box tw:!h-[calc(100%-48px)] tw:min-h-56 tw:border-none'
|
||||
>
|
||||
{item.layer.itemType.show_start_end_input && (
|
||||
<PopupStartEndInput
|
||||
item={item}
|
||||
showLabels={false}
|
||||
updateEndValue={(e) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
end: e,
|
||||
}))
|
||||
}
|
||||
updateStartValue={(s) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
start: s,
|
||||
}))
|
||||
}
|
||||
></PopupStartEndInput>
|
||||
)}
|
||||
<div
|
||||
className={`tw:flex tw:flex-col tw:h-full ${item.layer.itemType.show_start_end_input && 'tw:pt-4'}`}
|
||||
>
|
||||
{item.layer.itemType.show_start_end_input && (
|
||||
<PopupStartEndInput
|
||||
item={item}
|
||||
showLabels={false}
|
||||
updateEndValue={(e) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
end: e,
|
||||
}))
|
||||
}
|
||||
updateStartValue={(s) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
start: s,
|
||||
}))
|
||||
}
|
||||
></PopupStartEndInput>
|
||||
)}
|
||||
|
||||
<TextAreaInput
|
||||
placeholder='about ...'
|
||||
defaultValue={item?.text ? item.text : ''}
|
||||
updateFormValue={(v) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
text: v,
|
||||
}))
|
||||
}
|
||||
containerStyle='tw-grow'
|
||||
inputStyle={`tw-h-full ${!item.layer.itemType.show_start_end_input && 'tw-border-t-0 tw-rounded-tl-none'}`}
|
||||
/>
|
||||
<div>
|
||||
<TextAreaInput
|
||||
placeholder='about ...'
|
||||
defaultValue={item?.text ? item.text : ''}
|
||||
updateFormValue={(v) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
text: v,
|
||||
}))
|
||||
}
|
||||
containerStyle='tw:grow'
|
||||
inputStyle={`tw:h-full ${!item.layer.itemType.show_start_end_input && 'tw:border-t-0 tw:rounded-tl-none'}`}
|
||||
/>
|
||||
<TextAreaInput
|
||||
placeholder='contact info ...'
|
||||
defaultValue={state.contact || ''}
|
||||
@ -111,110 +111,108 @@ export const TabsForm = ({
|
||||
contact: c,
|
||||
}))
|
||||
}
|
||||
inputStyle='tw-h-24'
|
||||
containerStyle='tw-pt-4'
|
||||
inputStyle=''
|
||||
containerStyle='tw:pt-4 tw:h-24 tw:flex-none'
|
||||
required={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{item.layer?.itemType.offers_and_needs && (
|
||||
<>
|
||||
<input
|
||||
type='radio'
|
||||
name='my_tabs_2'
|
||||
role='tab'
|
||||
className={
|
||||
'tw-tab tw-min-w-[10em] [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]'
|
||||
}
|
||||
aria-label='Offers & Needs'
|
||||
checked={activeTab === 3 && true}
|
||||
onChange={() => updateActiveTab(3)}
|
||||
/>
|
||||
<div
|
||||
role='tabpanel'
|
||||
className='tw-tab-content tw-bg-base-100 tw-border-[var(--fallback-bc,oklch(var(--bc)/0.2))] tw-rounded-box tw-h-[calc(100dvh-332px)] tw-min-h-56 tw-border-none'
|
||||
>
|
||||
<div className='tw-h-full'>
|
||||
<div className='tw-w-full tw-h-[calc(50%-0.75em)] tw-mb-4'>
|
||||
<TagsWidget
|
||||
defaultTags={state.offers}
|
||||
onUpdate={(v) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
offers: v,
|
||||
}))
|
||||
}
|
||||
placeholder='enter your offers'
|
||||
containerStyle='tw-bg-transparent tw-w-full tw-h-full tw-mt-3 tw-text-xs tw-h-[calc(100%-1rem)] tw-min-h-[5em] tw-pb-2 tw-overflow-auto'
|
||||
/>
|
||||
</div>
|
||||
<div className='tw-w-full tw-h-[calc(50%-1.5em)]'>
|
||||
<TagsWidget
|
||||
defaultTags={state.needs}
|
||||
onUpdate={(v) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
needs: v,
|
||||
}))
|
||||
}
|
||||
placeholder='enter your needs'
|
||||
containerStyle='tw-bg-transparent tw-w-full tw-h-full tw-mt-3 tw-text-xs tw-h-[calc(100%-1rem)] tw-min-h-[5em] tw-pb-2 tw-overflow-auto'
|
||||
/>
|
||||
{item.layer?.itemType.offers_and_needs && (
|
||||
<>
|
||||
<input
|
||||
type='radio'
|
||||
name='my_tabs_2'
|
||||
role='tab'
|
||||
className={'tw:tab tw:min-w-[10em] '}
|
||||
aria-label='Offers & Needs'
|
||||
checked={activeTab === 3 && true}
|
||||
onChange={() => updateActiveTab(3)}
|
||||
/>
|
||||
<div
|
||||
role='tabpanel'
|
||||
className='tw:tab-content tw:bg-base-100 tw:border-(--fallback-bc,oklch(var(--bc)/0.2)) tw:rounded-box tw:!h-[calc(100%-48px)] tw:min-h-56 tw:border-none'
|
||||
>
|
||||
<div className='tw:h-full'>
|
||||
<div className='tw:w-full tw:h-[calc(50%-0.75em)] tw:mb-4'>
|
||||
<TagsWidget
|
||||
defaultTags={state.offers}
|
||||
onUpdate={(v) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
offers: v,
|
||||
}))
|
||||
}
|
||||
placeholder='enter your offers'
|
||||
containerStyle='tw:bg-transparent tw:w-full tw:h-full tw:mt-3 tw:text-xs tw:h-[calc(100%-1rem)] tw:min-h-[5em] tw:pb-2 tw:overflow-auto'
|
||||
/>
|
||||
</div>
|
||||
<div className='tw:w-full tw:h-[calc(50%-1.5em)]'>
|
||||
<TagsWidget
|
||||
defaultTags={state.needs}
|
||||
onUpdate={(v) =>
|
||||
setState((prevState) => ({
|
||||
...prevState,
|
||||
needs: v,
|
||||
}))
|
||||
}
|
||||
placeholder='enter your needs'
|
||||
containerStyle='tw:bg-transparent tw:w-full tw:h-full tw:mt-3 tw:text-xs tw:h-[calc(100%-1rem)] tw:min-h-[5em] tw:pb-2 tw:overflow-auto'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{item.layer?.itemType.relations && (
|
||||
<>
|
||||
<input
|
||||
type='radio'
|
||||
name='my_tabs_2'
|
||||
role='tab'
|
||||
className='tw-tab [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]'
|
||||
aria-label='Links'
|
||||
checked={activeTab === 7 && true}
|
||||
onChange={() => updateActiveTab(7)}
|
||||
/>
|
||||
<div
|
||||
role='tabpanel'
|
||||
className='tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-332px)] tw-overflow-y-auto tw-pt-4 tw-pb-1 -tw-mx-4 tw-overflow-x-hidden fade'
|
||||
>
|
||||
<div className='tw-h-full'>
|
||||
<div className='tw-grid tw-grid-cols-1 sm:tw-grid-cols-2 md:tw-grid-cols-1 lg:tw-grid-cols-1 xl:tw-grid-cols-1 2xl:tw-grid-cols-2 tw-mb-4'>
|
||||
{state.relations &&
|
||||
state.relations.map((i) => (
|
||||
<div
|
||||
key={i.id}
|
||||
className='tw-cursor-pointer tw-card tw-bg-base-200 tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl tw-text-base-content tw-mx-4 tw-p-6 tw-mb-4'
|
||||
onClick={() => navigate('/item/' + i.id)}
|
||||
>
|
||||
<LinkedItemsHeaderView
|
||||
unlinkPermission={updatePermission}
|
||||
item={i}
|
||||
unlinkCallback={(id) => unlinkItem(id, item, updateItem)}
|
||||
loading={loading}
|
||||
/>
|
||||
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
|
||||
<TextView truncate itemId={item.id} />
|
||||
</>
|
||||
)}
|
||||
{item.layer?.itemType.relations && (
|
||||
<>
|
||||
<input
|
||||
type='radio'
|
||||
name='my_tabs_2'
|
||||
role='tab'
|
||||
className='tw:tab '
|
||||
aria-label='Links'
|
||||
checked={activeTab === 7 && true}
|
||||
onChange={() => updateActiveTab(7)}
|
||||
/>
|
||||
<div
|
||||
role='tabpanel'
|
||||
className='tw:tab-content tw:rounded-box tw:!h-[calc(100%-48px)] tw:overflow-y-auto tw:pt-4 tw:overflow-x-hidden fade'
|
||||
>
|
||||
<div className='tw:h-full'>
|
||||
<div className='tw:grid tw:grid-cols-1 tw:sm:grid-cols-2 tw:md:grid-cols-1 tw:lg:grid-cols-1 tw:xl:grid-cols-1 tw:2xl:grid-cols-2 tw:mb-4'>
|
||||
{state.relations &&
|
||||
state.relations.map((i) => (
|
||||
<div
|
||||
key={i.id}
|
||||
className='tw:cursor-pointer tw:card tw:bg-base-200 tw:border-[1px] tw:border-base-300 tw:card-body tw:shadow-xl tw:text-base-content tw:mx-4 tw:p-6 tw:mb-4'
|
||||
onClick={() => navigate('/item/' + i.id)}
|
||||
>
|
||||
<LinkedItemsHeaderView
|
||||
unlinkPermission={updatePermission}
|
||||
item={i}
|
||||
unlinkCallback={(id) => unlinkItem(id, item, updateItem)}
|
||||
loading={loading}
|
||||
/>
|
||||
<div className='tw:overflow-y-auto tw:overflow-x-hidden tw:max-h-64 fade'>
|
||||
<TextView truncate itemId={item.id} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{updatePermission && (
|
||||
<ActionButton
|
||||
customStyle='!tw-bottom-24'
|
||||
collection='items'
|
||||
item={item}
|
||||
existingRelations={state.relations}
|
||||
triggerItemSelected={(id) => linkItem(id, item, updateItem)}
|
||||
></ActionButton>
|
||||
)}
|
||||
))}
|
||||
{updatePermission && (
|
||||
<ActionButton
|
||||
customStyle='tw:bottom-24!'
|
||||
collection='items'
|
||||
item={item}
|
||||
existingRelations={state.relations}
|
||||
triggerItemSelected={(id) => linkItem(id, item, updateItem)}
|
||||
></ActionButton>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -85,29 +85,27 @@ export const TabsView = ({
|
||||
}, [location.search])
|
||||
|
||||
return (
|
||||
<div role='tablist' className='tw-tabs tw-tabs-lifted tw-mt-2 tw-mb-2 tw-px-6'>
|
||||
<div role='tablist' className='tw:tabs tw:tabs-lift tw:mt-2 tw:mb-2 tw:px-6'>
|
||||
<input
|
||||
type='radio'
|
||||
name='my_tabs_2'
|
||||
role='tab'
|
||||
className={
|
||||
'tw-tab tw-font-bold !tw-ps-2 !tw-pe-2 [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]'
|
||||
}
|
||||
className={'tw:tab tw:font-bold tw:ps-2! tw:pe-2! '}
|
||||
aria-label={`${item.layer?.itemType.icon_as_labels && activeTab !== 1 ? '📝' : '📝\u00A0Info'}`}
|
||||
checked={activeTab === 1 && true}
|
||||
onChange={() => updateActiveTab(1)}
|
||||
/>
|
||||
<div
|
||||
role='tabpanel'
|
||||
className='tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-280px)] tw-overflow-y-auto fade tw-pt-2 tw-pb-4 tw-mb-4 tw-overflow-x-hidden'
|
||||
className='tw:tab-content tw:bg-base-100 tw:rounded-box tw:!h-[calc(100dvh-280px)] tw:overflow-y-auto fade tw:pt-2 tw:pb-4 tw:mb-4 tw:overflow-x-hidden'
|
||||
>
|
||||
{item.layer?.itemType.show_start_end && (
|
||||
<div className='tw-max-w-xs'>
|
||||
<div className='tw:max-w-xs'>
|
||||
<StartEndView item={item}></StartEndView>
|
||||
</div>
|
||||
)}
|
||||
<TextView text={item.text} itemId={item.id} />
|
||||
<div className='tw-h-4'></div>
|
||||
<div className='tw:h-4'></div>
|
||||
<TextView text={item.contact} itemId={item.id} />
|
||||
</div>
|
||||
{item.layer?.itemType.questlog && (
|
||||
@ -116,18 +114,16 @@ export const TabsView = ({
|
||||
type='radio'
|
||||
name='my_tabs_2'
|
||||
role='tab'
|
||||
className={
|
||||
'tw-tab tw-font-bold !tw-ps-2 !tw-pe-2 [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]'
|
||||
}
|
||||
className={'tw:tab tw:font-bold tw:ps-2! tw:pe-2!'}
|
||||
aria-label={`${item.layer.itemType.icon_as_labels && activeTab !== 2 ? '❤️' : '❤️\u00A0Trust'}`}
|
||||
checked={activeTab === 2 && true}
|
||||
onChange={() => updateActiveTab(2)}
|
||||
/>
|
||||
<div
|
||||
role='tabpanel'
|
||||
className='tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-280px)] tw-overflow-y-auto fade tw-pt-2 tw-pb-4 tw-mb-4 tw-overflow-x-hidden'
|
||||
className='tw:tab-content tw:bg-base-100 tw:rounded-box tw:!h-[calc(100dvh-280px)] tw:overflow-y-auto fade tw:pt-2 tw:pb-4 tw:mb-4 tw:overflow-x-hidden'
|
||||
>
|
||||
<table className='sm:tw-table-sm md:tw-table-md'>
|
||||
<table className='sm:tw:table-sm md:tw:table-md tw:w-full'>
|
||||
<tbody>
|
||||
{attestations
|
||||
.filter((a) => a.to.some((t) => t.directus_users_id === item.user_created?.id))
|
||||
@ -139,13 +135,15 @@ export const TabsView = ({
|
||||
<tr key={i}>
|
||||
<td>
|
||||
<div
|
||||
className={`tw-cursor-pointer tw-text-3xl tw-mask tw-mask-${a.shape} tw-p-3 tw-mr-2 tw-shadow-xl tw-bg-[${a.color}]`}
|
||||
className={`tw:cursor-pointer tw:text-3xl tw:mask ${a.shape === 'squircle' ? 'tw:mask-squircle' : a.shape === 'circle' ? 'tw:mask-circle' : 'tw:mask-hexagon-2'} tw:p-2 tw:my-2 tw:mr-2 tw:shadow-xl`}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
style={{ backgroundColor: a.color }}
|
||||
>
|
||||
{a.emoji}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className='tw-mr-2'>
|
||||
<div className='tw:mr-2'>
|
||||
<i>{a.text}</i>
|
||||
</div>
|
||||
</td>
|
||||
@ -153,8 +151,8 @@ export const TabsView = ({
|
||||
{getUserProfile(a.user_created.id) ? (
|
||||
<Link to={'/item/' + getUserProfile(a.user_created.id)?.id}>
|
||||
<div className='flex items-center gap-3'>
|
||||
<div className='tw-avatar'>
|
||||
<div className='tw-mask tw-rounded-full tw-h-8 tw-w-8 tw-mr-2'>
|
||||
<div className='tw:avatar'>
|
||||
<div className='tw:mask tw:rounded-full tw:h-8 tw:w-8 tw:mr-2'>
|
||||
{getUserProfile(a.user_created.id)?.image && (
|
||||
<img
|
||||
src={
|
||||
@ -171,7 +169,7 @@ export const TabsView = ({
|
||||
{getUserProfile(a.user_created.id)?.name ??
|
||||
a.user_created.first_name}{' '}
|
||||
</div>
|
||||
<div className='tw-text-xs opacity-50 tw-text-zinc-500'>
|
||||
<div className='tw:text-xs opacity-50 tw:text-zinc-500'>
|
||||
{timeAgo(a.date_created)}
|
||||
</div>
|
||||
</div>
|
||||
@ -180,7 +178,7 @@ export const TabsView = ({
|
||||
) : (
|
||||
<div>
|
||||
<div className='font-bold'>{a.user_created.first_name} </div>
|
||||
<div className='tw-text-xs opacity-50 tw-text-zinc-500'>
|
||||
<div className='tw:text-xs opacity-50 tw:text-zinc-500'>
|
||||
{timeAgo(a.date_created)}
|
||||
</div>
|
||||
</div>
|
||||
@ -199,21 +197,21 @@ export const TabsView = ({
|
||||
type='radio'
|
||||
name='my_tabs_2'
|
||||
role='tab'
|
||||
className={`tw-tab tw-font-bold !tw-ps-2 !tw-pe-2 ${!(item.layer.itemType.icon_as_labels && activeTab !== 3) && 'tw-min-w-[10.4em]'} [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]`}
|
||||
className={`tw:tab tw:font-bold tw:ps-2! tw:pe-2! ${!(item.layer.itemType.icon_as_labels && activeTab !== 3) && 'tw:min-w-[10.4em]'} `}
|
||||
aria-label={`${item.layer.itemType.icon_as_labels && activeTab !== 3 ? '♻️' : '♻️\u00A0Offers & Needs'}`}
|
||||
checked={activeTab === 3 && true}
|
||||
onChange={() => updateActiveTab(3)}
|
||||
/>
|
||||
<div
|
||||
role='tabpanel'
|
||||
className='tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-268px)] tw-overflow-y-auto fade tw-pt-4 tw-pb-1'
|
||||
className='tw:tab-content tw:bg-base-100 tw:rounded-box tw:h-[calc(100dvh-268px)] tw:overflow-y-auto fade tw:pt-4 tw:pb-1'
|
||||
>
|
||||
<div className='tw-h-full'>
|
||||
<div className='tw-grid tw-grid-cols-1'>
|
||||
<div className='tw:h-full'>
|
||||
<div className='tw:grid tw:grid-cols-1'>
|
||||
{offers.length > 0 ? (
|
||||
<div className='tw-col-span-1'>
|
||||
<h3 className='-tw-mb-2'>Offers</h3>
|
||||
<div className='tw-flex tw-flex-wrap tw-mb-4'>
|
||||
<div className='tw:col-span-1'>
|
||||
<h3 className='tw:-mb-2'>Offers</h3>
|
||||
<div className='tw:flex tw:flex-wrap tw:mb-4'>
|
||||
{offers.map((o) => (
|
||||
<TagView
|
||||
key={o.id}
|
||||
@ -229,9 +227,9 @@ export const TabsView = ({
|
||||
''
|
||||
)}
|
||||
{needs.length > 0 ? (
|
||||
<div className='tw-col-span-1'>
|
||||
<h3 className='-tw-mb-2 tw-col-span-1'>Needs</h3>
|
||||
<div className='tw-flex tw-flex-wrap tw-mb-4'>
|
||||
<div className='tw:col-span-1'>
|
||||
<h3 className='tw:-mb-2 tw:col-span-1'>Needs</h3>
|
||||
<div className='tw:flex tw:flex-wrap tw:mb-4'>
|
||||
{needs.map((n) => (
|
||||
<TagView key={n.id} tag={n} onClick={() => addFilterTag(n)} />
|
||||
))}
|
||||
@ -252,22 +250,22 @@ export const TabsView = ({
|
||||
type='radio'
|
||||
name='my_tabs_2'
|
||||
role='tab'
|
||||
className='tw-tab tw-font-bold !tw-ps-2 !tw-pe-2 [--tab-border-color:var(--fallback-bc,oklch(var(--bc)/0.2))]'
|
||||
className='tw:tab tw:font-bold tw:ps-2! tw:pe-2! '
|
||||
aria-label={`${item.layer.itemType.icon_as_labels && activeTab !== 7 ? '🔗' : '🔗\u00A0Links'}`}
|
||||
checked={activeTab === 7 && true}
|
||||
onChange={() => updateActiveTab(7)}
|
||||
/>
|
||||
<div
|
||||
role='tabpanel'
|
||||
className='tw-tab-content tw-bg-base-100 tw-rounded-box tw-h-[calc(100dvh-280px)] tw-overflow-y-auto tw-pt-4 tw-pb-1 -tw-mr-4 -tw-mb-4 tw-overflow-x-hidden'
|
||||
className='tw:tab-content tw:bg-base-100 tw:rounded-box tw:!h-[calc(100dvh-280px)] tw:overflow-y-auto tw:pt-4 tw:pb-1 tw:-mr-4 tw:-mb-4 tw:overflow-x-hidden'
|
||||
>
|
||||
<div className='tw-h-full'>
|
||||
<div className='tw-grid tw-grid-cols-1 sm:tw-grid-cols-2 md:tw-grid-cols-1 lg:tw-grid-cols-1 xl:tw-grid-cols-1 2xl:tw-grid-cols-2 tw-pb-4'>
|
||||
<div className='tw:h-full'>
|
||||
<div className='tw:grid tw:grid-cols-1 tw:sm:grid-cols-2 tw:md:grid-cols-1 tw:lg:grid-cols-1 tw:xl:grid-cols-1 tw:2xl:grid-cols-2 tw:pb-4'>
|
||||
{relations &&
|
||||
relations.map((i) => (
|
||||
<div
|
||||
key={i.id}
|
||||
className='tw-cursor-pointer tw-card tw-bg-base-200 tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl tw-text-base-content tw-p-6 tw-mr-4 tw-mb-4'
|
||||
className='tw:cursor-pointer tw:card tw:bg-base-200 tw:border-[1px] tw:border-base-300 tw:card-body tw:shadow-xl tw:text-base-content tw:p-6 tw:mr-4 tw:mb-4'
|
||||
onClick={() => navigate('/item/' + i.id)}
|
||||
>
|
||||
<LinkedItemsHeaderView
|
||||
@ -276,7 +274,7 @@ export const TabsView = ({
|
||||
unlinkCallback={unlinkItem}
|
||||
loading={loading}
|
||||
/>
|
||||
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
|
||||
<div className='tw:overflow-y-auto tw:overflow-x-hidden tw:max-h-64 fade'>
|
||||
<TextView truncate text={i.text} itemId={item.id} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -53,11 +53,11 @@ export function UserSettings() {
|
||||
return (
|
||||
<MapOverlayPage
|
||||
backdrop
|
||||
className='tw-mx-4 tw-mt-4 tw-max-h-[calc(100dvh-96px)] tw-h-fit md:tw-w-[calc(50%-32px)] tw-w-[calc(100%-32px)] tw-max-w-xl !tw-left-auto tw-top-0 tw-bottom-0'
|
||||
className='tw:mx-4 tw:mt-4 tw:max-h-[calc(100dvh-96px)] tw:h-fit tw:md:w-[calc(50%-32px)] tw:w-[calc(100%-32px)] tw:max-w-xl tw:left-auto! tw:top-0 tw:bottom-0'
|
||||
>
|
||||
<div className={'tw-text-xl tw-font-semibold'}>Settings</div>
|
||||
<div className='tw-divider tw-mt-2'></div>
|
||||
<div className='tw-grid tw-grid-cols-1 tw-gap-6'>
|
||||
<div className={'tw:text-xl tw:font-semibold'}>Settings</div>
|
||||
<div className='tw:divider tw:mt-2'></div>
|
||||
<div className='tw:grid tw:grid-cols-1 tw:gap-6'>
|
||||
<TextInput
|
||||
type='email'
|
||||
placeholder='new E-Mail'
|
||||
@ -76,12 +76,12 @@ export function UserSettings() {
|
||||
{/* <ToogleInput updateType="syncData" labelTitle="Sync Data" defaultValue={true} updateFormValue={updateFormValue}/> */}
|
||||
</div>
|
||||
|
||||
<div className='tw-mt-8'>
|
||||
<div className='tw:mt-8'>
|
||||
<button
|
||||
className={
|
||||
loading
|
||||
? ' tw-loading tw-btn-disabled tw-btn tw-btn-primary tw-float-right'
|
||||
: 'tw-btn tw-btn-primary tw-float-right'
|
||||
? ' tw:loading tw:btn-disabled tw:btn tw:btn-primary tw:float-right'
|
||||
: 'tw:btn tw:btn-primary tw:float-right'
|
||||
}
|
||||
onClick={() => onUpdateUser()}
|
||||
>
|
||||
|
||||
@ -88,16 +88,16 @@ export const AttestationForm = ({ api }: { api?: ItemsApi<unknown> }) => {
|
||||
const [selectedColor, setSelectedColor] = useState('#fff0d6')
|
||||
|
||||
return (
|
||||
<MapOverlayPage backdrop className='tw-h-fit tw-min-h-56 tw-w-96'>
|
||||
<div className='tw-text-center tw-text-xl tw-font-bold'>Gratitude</div>
|
||||
<div className='tw-text-center tw-text-base tw-text-gray-400'>to</div>
|
||||
<div className='tw-flex tw-flex-row tw-justify-center tw-items-center tw-flex-wrap'>
|
||||
<MapOverlayPage backdrop className='tw:h-fit tw:min-h-56 tw:w-96'>
|
||||
<div className='tw:text-center tw:text-xl tw:font-bold'>Gratitude</div>
|
||||
<div className='tw:text-center tw:text-base tw:text-gray-400'>to</div>
|
||||
<div className='tw:flex tw:flex-row tw:justify-center tw:items-center tw:flex-wrap'>
|
||||
{users?.map(
|
||||
(u, k) => (
|
||||
<div key={k} className='tw-flex tw-items-center tw-space-x-3 tw-mx-2 tw-my-1'>
|
||||
<div key={k} className='tw:flex tw:items-center tw:space-x-3 tw:mx-2 tw:my-1'>
|
||||
{u.image ? (
|
||||
<div className='tw-avatar'>
|
||||
<div className='tw-mask tw-mask-circle tw-w-8 tw-h-8'>
|
||||
<div className='tw:avatar'>
|
||||
<div className='tw:mask tw:mask-circle tw:w-8 tw:h-8'>
|
||||
<img
|
||||
src={appState.assetsApi.url + u.image + '?width=40&heigth=40'}
|
||||
alt='Avatar'
|
||||
@ -105,10 +105,10 @@ export const AttestationForm = ({ api }: { api?: ItemsApi<unknown> }) => {
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className='tw-mask tw-mask-circle tw-text-xl md:tw-text-2xl tw-bg-slate-200 tw-rounded-full tw-w-8 tw-h-8'></div>
|
||||
<div className='tw:mask tw:mask-circle tw:text-xl tw:md:text-2xl tw:bg-slate-200 tw:rounded-full tw:w-8 tw:h-8'></div>
|
||||
)}
|
||||
<div>
|
||||
<div className='tw-font-bold'>{u.name}</div>
|
||||
<div className='tw:font-bold'>{u.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
@ -116,9 +116,9 @@ export const AttestationForm = ({ api }: { api?: ItemsApi<unknown> }) => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className='tw-w-full'>
|
||||
<div className='tw-flex tw-justify-center tw-items-center'>
|
||||
<div className=' tw-flex tw-justify-center tw-items-center tw-w-28 tw-h-28 tw-m-4'>
|
||||
<div className='tw:w-full'>
|
||||
<div className='tw:flex tw:justify-center tw:items-center'>
|
||||
<div className=' tw:flex tw:justify-center tw:items-center tw:w-28 tw:h-28 tw:m-4'>
|
||||
<EmojiPicker
|
||||
selectedEmoji={selectedEmoji}
|
||||
selectedColor={selectedColor}
|
||||
@ -129,19 +129,19 @@ export const AttestationForm = ({ api }: { api?: ItemsApi<unknown> }) => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='tw-flex tw-justify-center tw-items-center'>
|
||||
<div className='tw:flex tw:justify-center tw:items-center'>
|
||||
<input
|
||||
ref={inputRef}
|
||||
value={inputValue}
|
||||
onChange={handleChange}
|
||||
type='text'
|
||||
placeholder='... and say some words'
|
||||
className='tw-input tw-min-w-0 tw-w-fit tw-resize-none tw-overflow-hidden tw-text-center '
|
||||
className='input tw:min-w-0 tw:w-fit tw:resize-none tw:overflow-hidden tw:text-center '
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='tw-w-full tw-grid tw-mt-4'>
|
||||
<button onClick={sendAttestation} className='tw-btn tw-place-self-center tw-px-8'>
|
||||
<div className='tw:w-full tw:grid tw:mt-4'>
|
||||
<button onClick={sendAttestation} className='tw:btn tw:place-self-center tw:px-8'>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -17,9 +17,9 @@ export function CardPage({
|
||||
parents?: { name: string; path: string }[]
|
||||
}) {
|
||||
return (
|
||||
<main className='tw-flex-1 tw-overflow-y-auto tw-overflow-x-hidden tw-pt-2 tw-px-6 tw-min-w-80 tw-flex tw-justify-center'>
|
||||
<div className='tw-w-full xl:tw-max-w-6xl '>
|
||||
<div className='tw-text-sm tw-breadcrumbs'>
|
||||
<main className='tw:flex-1 tw:overflow-y-auto tw:overflow-x-hidden tw:pt-2 tw:px-6 tw:min-w-80 tw:flex tw:justify-center'>
|
||||
<div className='tw:w-full tw:xl:max-w-6xl '>
|
||||
<div className='tw:text-sm breadcrumbs'>
|
||||
<ul>
|
||||
<li>
|
||||
<Link to={'/'}>Home</Link>
|
||||
@ -32,7 +32,7 @@ export function CardPage({
|
||||
<li>{title}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<TitleCard hideTitle={hideTitle} title={title} topMargin='tw-my-2' className=' tw-mb-4'>
|
||||
<TitleCard hideTitle={hideTitle} title={title} topMargin='tw:my-2' className=' tw:mb-4'>
|
||||
{children}
|
||||
</TitleCard>
|
||||
</div>
|
||||
|
||||
@ -8,24 +8,24 @@ export const DateUserInfo = ({ item }: { item: Item }) => {
|
||||
const [infoExpanded, setInfoExpanded] = useState<boolean>(false)
|
||||
return (
|
||||
<div
|
||||
className='tw-flex -tw-mb-1 tw-flex-row tw-mr-2 -tw-mt-2'
|
||||
className='tw:flex tw:-mb-1 tw:flex-row tw:mr-2 tw:-mt-2'
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{infoExpanded ? (
|
||||
<p
|
||||
className={'tw-italic tw-min-h-[21px] !tw-my-0 tw-text-gray-500'}
|
||||
className={'tw:italic tw:min-h-[21px] tw:my-0! tw:text-gray-500'}
|
||||
onClick={() => setInfoExpanded(false)}
|
||||
// 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!)}`}</p>
|
||||
) : (
|
||||
<p
|
||||
className='!tw-my-0 tw-min-h-[21px] tw-font-bold tw-cursor-pointer tw-text-gray-500'
|
||||
className='tw:my-0! tw:min-h-[21px] tw:font-bold tw:cursor-pointer tw:text-gray-500'
|
||||
onClick={() => setInfoExpanded(true)}
|
||||
>
|
||||
ⓘ
|
||||
</p>
|
||||
)}
|
||||
<div className='tw-grow '></div>
|
||||
<div className='tw:grow '></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -32,11 +32,11 @@ const DialogModal = ({
|
||||
useEffect(() => {
|
||||
if (isOpened) {
|
||||
ref.current?.showModal()
|
||||
ref.current?.classList.remove('tw-hidden')
|
||||
ref.current?.classList.remove('tw:hidden')
|
||||
document.body.classList.add('modal-open') // prevent bg scroll
|
||||
} else {
|
||||
ref.current?.close()
|
||||
ref.current?.classList.add('tw-hidden')
|
||||
ref.current?.classList.add('tw:hidden')
|
||||
document.body.classList.remove('modal-open')
|
||||
}
|
||||
}, [isOpened])
|
||||
@ -44,20 +44,20 @@ const DialogModal = ({
|
||||
if (isOpened) {
|
||||
return (
|
||||
<dialog
|
||||
className={`${className ?? ''} tw-card tw-shadow-xl tw-absolute tw-right-0 tw-top-0 tw-bottom-0 tw-left-0 tw-m-auto tw-transition-opacity tw-duration-300 tw-p-4 tw-max-w-xl tw-bg-base-100`}
|
||||
className={`${className ?? ''} card tw:shadow-xl tw:absolute tw:right-0 tw:top-0 tw:bottom-0 tw:left-0 tw:m-auto tw:transition-opacity tw:duration-300 tw:p-4 tw:max-w-xl tw:bg-base-100`}
|
||||
ref={ref}
|
||||
onCancel={onClose}
|
||||
onClick={(e) =>
|
||||
ref.current && !isClickInsideRectangle(e, ref.current) && closeOnClickOutside && onClose()
|
||||
}
|
||||
>
|
||||
<div className='tw-card-body tw-p-2'>
|
||||
<h2 className='tw-text-2xl tw-font-semibold tw-mb-2 tw-text-center'>{title}</h2>
|
||||
<div className='card-body tw:p-2'>
|
||||
<h2 className='tw:text-2xl tw:font-semibold tw:mb-2 tw:text-center'>{title}</h2>
|
||||
|
||||
{children}
|
||||
{showCloseButton && (
|
||||
<button
|
||||
className='tw-btn tw-btn-sm tw-btn-circle tw-btn-ghost tw-absolute tw-right-2 tw-top-2'
|
||||
className='btn btn-sm btn-circle btn-ghost tw:absolute tw:right-2 tw:top-2'
|
||||
onClick={onClose}
|
||||
>
|
||||
✕
|
||||
|
||||
@ -97,45 +97,51 @@ export const EmojiPicker = ({
|
||||
<>
|
||||
<div
|
||||
onClick={toggleDropdown}
|
||||
className={`tw-cursor-pointer ${selectedEmoji === 'select badge' ? 'tw-text-sm !tw-p-9 tw-text-center ' : 'tw-text-6xl'} tw-mask tw-mask-${selectedShape} tw-p-6 tw-bg-[${selectedColor}]`}
|
||||
className={`tw:cursor-pointer ${selectedEmoji === 'select badge' ? 'tw:text-sm tw:p-9! tw:text-center ' : 'tw:text-6xl'} tw:mask tw:mask-${selectedShape} tw:p-6`}
|
||||
style={{ backgroundColor: selectedColor }}
|
||||
>
|
||||
{selectedEmoji}
|
||||
</div>
|
||||
|
||||
{isOpen && (
|
||||
<div className='tw-absolute tw-z-3000 tw-top-0 tw-left-1/2 tw-transform tw--translate-x-1/2 tw-mt-12 tw-bg-base-100 tw-rounded-2xl tw-shadow-lg tw-p-2 tw-w-full'>
|
||||
<div className='tw-grid tw-grid-cols-6 tw-gap-2 tw-pb-2'>
|
||||
<div className='tw:absolute tw:z-3000 tw:top-0 tw:left-1/2 tw:transform tw:-translate-x-1/2 tw:mt-12 tw:bg-base-100 tw:rounded-2xl tw:shadow-lg tw:p-2 tw:w-full'>
|
||||
<div className='tw:grid tw:grid-cols-6 tw:gap-2 tw:pb-2'>
|
||||
{emojis.map((emoji) => (
|
||||
<button
|
||||
key={emoji}
|
||||
onClick={() => 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 tw:hover:bg-base-200 tw:rounded-md ${emoji === selectedEmoji ? 'tw:bg-base-300' : ''}`}
|
||||
>
|
||||
{emoji}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<hr />
|
||||
<div className='tw-grid tw-grid-cols-3 tw-gap-2 tw-py-2'>
|
||||
<div className='tw:grid tw:grid-cols-3 tw:gap-2 tw:py-2'>
|
||||
{shapes.map((shape) => (
|
||||
<div
|
||||
key={shape}
|
||||
className={`tw-cursor-pointer hover:tw-bg-base-200 tw-rounded-md tw-p-2 ${shape === selectedShape ? 'tw-bg-base-300' : ''}`}
|
||||
className={`tw:cursor-pointer tw:hover:bg-base-200 tw:rounded-md tw:p-2 ${shape === selectedShape ? 'tw:bg-base-300' : ''}`}
|
||||
onClick={() => selectShape(shape)}
|
||||
>
|
||||
<div className={`tw-h-12 tw-mask tw-mask-${shape} tw-bg-neutral-content`}></div>
|
||||
<div
|
||||
className={`tw:h-12 tw:w-full tw:mask ${shape === 'squircle' ? 'tw:mask-squircle' : shape === 'circle' ? 'tw:mask-circle' : 'tw:mask-hexagon-2'} tw:bg-neutral-content`}
|
||||
></div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<hr />
|
||||
<div className='tw-grid tw-grid-cols-6 tw-gap-2 tw-py-2 tw-px-6'>
|
||||
<div className='tw:grid tw:grid-cols-6 tw:gap-2 tw:py-2 tw:px-6'>
|
||||
{colors.map((color) => (
|
||||
<div
|
||||
key={color}
|
||||
className={`tw-cursor-pointer hover:tw-bg-base-200 tw-rounded-md tw-p-2 tw-flex tw-justify-center tw-items-center ${color === selectedColor ? 'tw-bg-base-300' : ''}`}
|
||||
className={`tw:cursor-pointer tw:hover:bg-base-200 tw:rounded-md tw:p-2 tw:flex tw:justify-center tw:items-center ${color === selectedColor ? 'tw:bg-base-300' : ''}`}
|
||||
onClick={() => selectColor(color)}
|
||||
>
|
||||
<div className={`tw-h-8 tw-w-8 tw-rounded-full tw-bg-[${color}]`}></div>
|
||||
<div
|
||||
className={`tw:h-8 tw:w-8 tw:rounded-full`}
|
||||
style={{ backgroundColor: color }}
|
||||
></div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@ -24,7 +24,7 @@ export const ItemCard = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className='tw-cursor-pointer tw-card tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl tw-bg-base-100 tw-text-base-content tw-p-4 tw-mb-4 tw-h-fit'
|
||||
className='tw:cursor-pointer tw:card tw:border-[1px] tw:border-base-300 tw:card-body tw:shadow-xl tw:bg-base-100 tw:text-base-content tw:p-4 tw:mb-4 tw:h-fit'
|
||||
onClick={() => {
|
||||
// We could have an onClick callback instead
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
@ -40,7 +40,7 @@ export const ItemCard = ({
|
||||
editCallback={() => navigate('/edit-item/' + i.id)}
|
||||
deleteCallback={() => deleteCallback(i)}
|
||||
></HeaderView>
|
||||
<div className='tw-overflow-y-auto tw-overflow-x-hidden tw-max-h-64 fade'>
|
||||
<div className='tw:overflow-y-auto tw:overflow-x-hidden tw:max-h-64 fade'>
|
||||
{i.layer?.itemType.show_start_end && <StartEndView item={i}></StartEndView>}
|
||||
{i.layer?.itemType.show_text && <TextView truncate text={i.text} itemId={i.id} />}
|
||||
</div>
|
||||
|
||||
@ -38,18 +38,18 @@ export function MapOverlayPage({
|
||||
}, [overlayRef, backdropRef])
|
||||
|
||||
return (
|
||||
<div className={`tw-absolute tw-h-full tw-w-full tw-m-auto ${backdrop ? 'tw-z-[2000]' : ''}`}>
|
||||
<div className={`tw:absolute tw:h-full tw:w-full tw:m-auto ${backdrop ? 'tw:z-2000' : ''}`}>
|
||||
<div
|
||||
ref={backdropRef}
|
||||
className={`${backdrop ? 'tw-backdrop-brightness-75' : ''} tw-h-full tw-w-full tw-grid tw-place-items-center tw-m-auto`}
|
||||
className={`${backdrop ? 'tw:backdrop-brightness-75' : ''} tw:h-full tw:w-full tw:grid tw:place-items-center tw:m-auto`}
|
||||
>
|
||||
<div
|
||||
ref={overlayRef}
|
||||
className={`${card ? 'tw-card tw-card-body' : ''} tw-shadow-xl tw-bg-base-100 tw-p-6 ${className ?? ''} ${backdrop ? '' : 'tw-z-[2000]'} tw-absolute tw-top-0 tw-bottom-0 tw-right-0 tw-left-0 tw-m-auto`}
|
||||
className={`${card ? 'tw:card tw:card-body' : ''} tw:shadow-xl tw:bg-base-100 tw:p-6 ${className ?? ''} ${backdrop ? '' : 'tw:z-2000'} tw:absolute tw:top-0 tw:bottom-0 tw:right-0 tw:left-0 tw:m-auto`}
|
||||
>
|
||||
{children}
|
||||
<button
|
||||
className='tw-btn tw-btn-sm tw-btn-circle tw-btn-ghost tw-absolute tw-right-2 tw-top-2'
|
||||
className='tw:btn tw:btn-sm tw:btn-circle tw:btn-ghost tw:absolute tw:right-2 tw:top-2'
|
||||
onClick={() => closeScreen()}
|
||||
>
|
||||
✕
|
||||
|
||||
@ -61,11 +61,11 @@ export const MarketView = () => {
|
||||
}, [items])
|
||||
|
||||
return (
|
||||
<MapOverlayPage className='tw-rounded-none tw-overflow-y-auto tw-bg-base-200 !tw-p-4'>
|
||||
<div className='tw-grid tw-grid-cols-1 md:tw-grid-cols-2'>
|
||||
<MapOverlayPage className='tw:rounded-none tw:overflow-y-auto tw:bg-base-200 tw:p-4!'>
|
||||
<div className='tw:grid tw:grid-cols-1 tw:md:grid-cols-2'>
|
||||
<div>
|
||||
<p className='tw-text-lg tw-font-bold'>Offers</p>
|
||||
<div className='tw-flex tw-flex-wrap'>
|
||||
<p className='tw:text-lg tw:font-bold'>Offers</p>
|
||||
<div className='tw:flex tw:flex-wrap'>
|
||||
{groupAndCount(offers).map((o) => (
|
||||
<TagView
|
||||
onClick={() => navigate(`/?tags=${o.object.name}`)}
|
||||
@ -77,8 +77,8 @@ export const MarketView = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p className='tw-text-lg tw-font-bold'>Needs</p>
|
||||
<div className='tw-flex tw-flex-wrap'>
|
||||
<p className='tw:text-lg tw:font-bold'>Needs</p>
|
||||
<div className='tw:flex tw:flex-wrap'>
|
||||
{groupAndCount(needs).map((o) => (
|
||||
<TagView
|
||||
onClick={() => navigate(`/?tags=${o.object.name}`)}
|
||||
|
||||
@ -128,16 +128,16 @@ export const OverlayItemsIndexPage = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<MapOverlayPage className='tw-rounded-none tw-overflow-y-auto tw-bg-base-200 !tw-p-4'>
|
||||
<div className='tw-flex tw-flex-col tw-h-full'>
|
||||
<div className='tw-flex-none'>
|
||||
<MapOverlayPage className='tw:rounded-none tw:overflow-y-auto tw:bg-base-200 tw:p-4!'>
|
||||
<div className='tw:flex tw:flex-col tw:h-full'>
|
||||
<div className='tw:flex-none'>
|
||||
<Control position='topLeft' zIndex='1000' absolute={false}>
|
||||
<SearchControl />
|
||||
<TagsControl />
|
||||
</Control>
|
||||
</div>
|
||||
<div className='tw-overflow-scroll fade tw-flex-1'>
|
||||
<div className='tw-columns-1 md:tw-columns-2 lg:tw-columns-3 2xl:tw-columns-4 tw-gap-6 tw-pt-4'>
|
||||
<div className='tw:overflow-scroll fade tw:flex-1'>
|
||||
<div className='tw:columns-1 tw:md:columns-2 tw:lg:columns-3 tw:2xl:columns-4 tw:gap-6 tw:pt-4'>
|
||||
{items
|
||||
.filter((i) => i.layer?.name === layerName)
|
||||
.filter((item) =>
|
||||
@ -165,7 +165,7 @@ export const OverlayItemsIndexPage = ({
|
||||
return dateB - dateA // Subtracts milliseconds which are numbers
|
||||
})
|
||||
.map((i, k) => (
|
||||
<div key={k} className='tw-break-inside-avoid tw-mb-6'>
|
||||
<div key={k} className='tw:break-inside-avoid tw:mb-6'>
|
||||
<ItemCard
|
||||
i={i}
|
||||
loading={loading}
|
||||
@ -176,12 +176,12 @@ export const OverlayItemsIndexPage = ({
|
||||
))}
|
||||
{addItemPopupType === 'place' && (
|
||||
<form ref={tabRef} autoComplete='off' onSubmit={(e) => submitNewItem(e)}>
|
||||
<div className='tw-cursor-pointer tw-break-inside-avoid tw-card tw-border-[1px] tw-border-base-300 tw-card-body tw-shadow-xl tw-bg-base-100 tw-text-base-content tw-p-6 tw-mb-10'>
|
||||
<div className='tw:cursor-pointer tw:break-inside-avoid card tw:border-[1px] tw:border-base-300 card-body tw:shadow-xl tw:bg-base-100 tw:text-base-content tw:p-6 tw:mb-10'>
|
||||
<label
|
||||
className='tw-btn tw-btn-sm tw-rounded-2xl tw-btn-circle tw-btn-ghost hover:tw-bg-transparent tw-absolute tw-right-0 tw-top-0 tw-text-gray-600'
|
||||
className='btn btn-sm tw:rounded-2xl btn-circle btn-ghost tw:hover:bg-transparent tw:absolute tw:right-0 tw:top-0 tw:text-gray-600'
|
||||
onClick={() => setAddItemPopupType('')}
|
||||
>
|
||||
<p className='tw-text-center'>✕</p>
|
||||
<p className='tw:text-center'>✕</p>
|
||||
</label>
|
||||
<TextInput
|
||||
type='text'
|
||||
@ -195,18 +195,18 @@ export const OverlayItemsIndexPage = ({
|
||||
placeholder='Text'
|
||||
dataField='text'
|
||||
defaultValue={''}
|
||||
inputStyle='tw-h-40 tw-mt-5'
|
||||
inputStyle='tw:h-40 tw:mt-5'
|
||||
/>
|
||||
<div className='tw-flex tw-justify-center'>
|
||||
<div className='tw:flex tw:justify-center'>
|
||||
<button
|
||||
className={
|
||||
loading
|
||||
? 'tw-btn tw-btn-disabled tw-mt-5 tw-place-self-center'
|
||||
: 'tw-btn tw-mt-5 tw-place-self-center'
|
||||
? 'btn btn-disabled tw:mt-5 tw:place-self-center'
|
||||
: 'btn tw:mt-5 tw:place-self-center'
|
||||
}
|
||||
type='submit'
|
||||
>
|
||||
{loading ? <span className='tw-loading tw-loading-spinner'></span> : 'Save'}
|
||||
{loading ? <span className='loading loading-spinner'></span> : 'Save'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -18,12 +18,12 @@ export const SelectUser = () => {
|
||||
const [selectedUsers, setSelectedUsers] = useState<string[]>([])
|
||||
|
||||
return (
|
||||
<MapOverlayPage backdrop className='tw-h-3/4 tw-w-80'>
|
||||
<div className='tw-text-center tw-text-xl tw-font-bold tw-mb-4'>Gratitude to ...</div>
|
||||
<MapOverlayPage backdrop className='tw:h-3/4 tw:w-80'>
|
||||
<div className='tw:text-center tw:text-xl tw:font-bold tw:mb-4'>Gratitude to ...</div>
|
||||
|
||||
{/* Team Member list in table format loaded constant */}
|
||||
<div className='tw-overflow-x-auto tw-w-full fade'>
|
||||
<table className='tw-table tw-w-full'>
|
||||
<div className='tw:overflow-x-auto tw:w-full fade'>
|
||||
<table className='tw:table tw:w-full'>
|
||||
<tbody>
|
||||
{users.map((u, k) => {
|
||||
return (
|
||||
@ -32,14 +32,14 @@ export const SelectUser = () => {
|
||||
<input
|
||||
type='checkbox'
|
||||
onChange={() => setSelectedUsers((prev) => [...prev, u.id])}
|
||||
className='tw-checkbox tw-checkbox-sm'
|
||||
className='checkbox checkbox-sm'
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<div className='tw-flex tw-items-center tw-space-x-3'>
|
||||
<div className='tw:flex tw:items-center tw:space-x-3'>
|
||||
{u.image ? (
|
||||
<div className='tw-avatar'>
|
||||
<div className='tw-mask tw-mask-circle tw-w-8 tw-h-8'>
|
||||
<div className='tw:avatar'>
|
||||
<div className='tw:mask tw:mask-circle tw:w-8 tw:h-8'>
|
||||
<img
|
||||
src={appState.assetsApi.url + u.image + '?width=40&heigth=40'}
|
||||
alt='Avatar'
|
||||
@ -47,10 +47,10 @@ export const SelectUser = () => {
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className='tw-mask tw-mask-circle tw-text-xl md:tw-text-2xl tw-bg-slate-200 tw-rounded-full tw-w-8 tw-h-8'></div>
|
||||
<div className='tw:mask tw:mask-circle tw:text-xl tw:md:text-2xl tw:bg-slate-200 tw:rounded-full tw:w-8 tw:h-8'></div>
|
||||
)}
|
||||
<div>
|
||||
<div className='tw-font-bold'>{u.name}</div>
|
||||
<div className='tw:font-bold'>{u.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
@ -60,12 +60,12 @@ export const SelectUser = () => {
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className='tw-w-full tw-grid tw-mt-4'>
|
||||
<div className='tw:w-full tw:grid tw:mt-4'>
|
||||
<Link
|
||||
className='tw-place-self-center '
|
||||
className='tw:place-self-center '
|
||||
to={'/attestation-form' + '?to=' + selectedUsers.map((u) => u, ',')}
|
||||
>
|
||||
<button className='tw-btn tw-px-8'>Next</button>
|
||||
<button className='tw:btn tw:px-8'>Next</button>
|
||||
</Link>
|
||||
</div>
|
||||
</MapOverlayPage>
|
||||
|
||||
@ -19,11 +19,11 @@ export const TagView = ({
|
||||
<div
|
||||
key={tag.name}
|
||||
onClick={onClick}
|
||||
className={`tw-flex tw-items-center tw-flex-row tw-rounded-2xl tw-text-white tw-p-2 tw-px-4 tw-shadow-xl tw-card tw-mt-3 tw-mr-4 tw-cursor-pointer tw-w-fit ${heighlight ? 'tw-border-4 tw-border-base-200 tw-shadow-lg' : ''}`}
|
||||
className={`tw:flex tw:items-center tw:flex-row tw:rounded-2xl tw:text-white tw:p-2 tw:px-4 tw:shadow-xl card tw:mt-3 tw:mr-4 tw:cursor-pointer tw:w-fit ${heighlight ? 'tw:border-4 tw:border-base-200 tw:shadow-lg' : ''}`}
|
||||
style={{ backgroundColor: tag.color ? tag.color : '#666' }}
|
||||
>
|
||||
<b>{decodeTag(tag.name)}</b>
|
||||
{count && <span className='tw-ml-2'>({count})</span>}
|
||||
{count && <span className='tw:ml-2'>({count})</span>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
63
src/Components/Templates/ThemeControl.tsx
Normal file
63
src/Components/Templates/ThemeControl.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
const themes = [
|
||||
'default',
|
||||
'light',
|
||||
'dark',
|
||||
'valentine',
|
||||
'retro',
|
||||
'aqua',
|
||||
'cyberpunk',
|
||||
'caramellatte',
|
||||
'abyss',
|
||||
'silk',
|
||||
]
|
||||
|
||||
export const ThemeControl = () => {
|
||||
const [theme, setTheme] = useState<string>(() => {
|
||||
const savedTheme = localStorage.getItem('theme')
|
||||
return savedTheme ? (JSON.parse(savedTheme) as string) : 'default'
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (theme !== 'default') {
|
||||
localStorage.setItem('theme', JSON.stringify(theme))
|
||||
} else localStorage.removeItem('theme')
|
||||
document.documentElement.setAttribute('data-theme', theme)
|
||||
}, [theme])
|
||||
|
||||
return (
|
||||
<div className='tw:dropdown tw:mr-2'>
|
||||
<div tabIndex={0} role='button' className='tw:btn tw:m-1'>
|
||||
Theme
|
||||
<svg
|
||||
width='12px'
|
||||
height='12px'
|
||||
className='tw:inline-block tw:h-2 tw:w-2 tw:fill-current tw:opacity-60'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
viewBox='0 0 2048 2048'
|
||||
>
|
||||
<path d='M1799 349l242 241-1017 1017L7 590l242-241 775 775 775-775z'></path>
|
||||
</svg>
|
||||
</div>
|
||||
<ul
|
||||
tabIndex={0}
|
||||
className='tw:dropdown-content tw:bg-base-200 tw:rounded-box tw:z-1 tw:w-36 tw:p-2 tw:shadow-2xl'
|
||||
>
|
||||
{themes.map((t) => (
|
||||
<li key={t}>
|
||||
<input
|
||||
className={`tw:btn ${theme === t ? 'tw:bg-base-300' : ''} tw:btn-sm tw:btn-block tw:btn-ghost tw:justify-start`}
|
||||
type='radio'
|
||||
name='theme'
|
||||
value={t}
|
||||
checked={theme === t}
|
||||
onChange={() => setTheme(t)}
|
||||
aria-label={t.toLowerCase()}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -23,28 +23,28 @@ export function TitleCard({
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
'tw-card tw-w-full tw-p-6 tw-bg-base-100 tw-shadow-xl tw-h-fit tw-mb-4 ' +
|
||||
'card tw:w-full tw:p-6 tw:bg-base-100 tw:shadow-xl tw:h-fit tw:mb-4 ' +
|
||||
(className ?? '') +
|
||||
' ' +
|
||||
(topMargin ?? 'tw-mt-6')
|
||||
(topMargin ?? 'tw:mt-6')
|
||||
}
|
||||
>
|
||||
{!hideTitle && (
|
||||
<>
|
||||
<Subtitle styleClass={TopSideButtons ? 'tw-inline-block' : ''}>
|
||||
<Subtitle styleClass={TopSideButtons ? 'tw:inline-block' : ''}>
|
||||
{title}
|
||||
|
||||
{/* Top side button, show only if present */}
|
||||
{TopSideButtons && (
|
||||
<div className='tw-inline-block tw-float-right'>{TopSideButtons}</div>
|
||||
<div className='tw:inline-block tw:float-right'>{TopSideButtons}</div>
|
||||
)}
|
||||
</Subtitle>
|
||||
<div className='tw-divider tw-mt-2'></div>
|
||||
<div className='divider tw:mt-2'></div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/** Card Body */}
|
||||
<div className='tw-h-full tw-bg-transparent tw-w-full tw-pb-6 tw-bg-base-100'>{children}</div>
|
||||
<div className='tw:h-full tw:bg-transparent tw:w-full tw:pb-6 tw:bg-base-100'>{children}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
function ErrorText({ styleClass, children }: { styleClass: string; children: React.ReactNode }) {
|
||||
return <p className={`tw-text-center tw-text-error ${styleClass}`}>{children}</p>
|
||||
return <p className={`tw:text-center tw:text-error ${styleClass}`}>{children}</p>
|
||||
}
|
||||
|
||||
export default ErrorText
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
function Subtitle({ styleClass, children }: { styleClass: string; children: React.ReactNode }) {
|
||||
return <div className={`tw-text-xl tw-font-semibold ${styleClass}`}>{children}</div>
|
||||
return <div className={`tw:text-xl tw:font-semibold ${styleClass}`}>{children}</div>
|
||||
}
|
||||
|
||||
export default Subtitle
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
viewBox='0 0 24 24'
|
||||
fill='white'
|
||||
className='tw-h-4 tw-w-4'
|
||||
className='h-4 w-4'
|
||||
>
|
||||
<path d='M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z' />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 310 B After Width: | Height: | Size: 304 B |
@ -20,26 +20,25 @@
|
||||
}
|
||||
|
||||
.leaflet-popup-content-wrapper, .leaflet-popup-tip{
|
||||
background-color: theme('colors.base-100');
|
||||
color: theme('colors.base-content');
|
||||
|
||||
background-color: var(--color-base-100);
|
||||
color: var(--color-base-content);
|
||||
border-radius: var(--radius-box);
|
||||
}
|
||||
|
||||
.leaflet-tooltip {
|
||||
background-color: theme('colors.base-100');
|
||||
color: theme('colors.base-content');
|
||||
background-color: var(--color-base-100);
|
||||
color: var(--color-base-content);
|
||||
border-width: 0px;
|
||||
}
|
||||
|
||||
.leaflet-tooltip {
|
||||
border-radius: 1em;
|
||||
border-radius: var(--radius-box);
|
||||
transition: opacity 500ms;
|
||||
transition-delay: 50ms;
|
||||
|
||||
}
|
||||
|
||||
.leaflet-tooltip-top::before {
|
||||
border-top-color: theme('colors.base-100');
|
||||
.leaflet-tooltip::before {
|
||||
border-top-color: var(--color-base-100);
|
||||
}
|
||||
|
||||
.leaflet-container {
|
||||
@ -48,4 +47,9 @@
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
background-position: 50% 80%;
|
||||
}
|
||||
|
||||
.leaflet-popup-close-button span {
|
||||
color: var(--color-base-content);
|
||||
opacity: 50%;
|
||||
}
|
||||
@ -1,24 +1,80 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@import 'tailwindcss' prefix(tw);
|
||||
@plugin "daisyui" {
|
||||
themes: light --default, dark --prefersdark, valentine, retro, aqua, cyberpunk, caramellatte, abyss, silk;
|
||||
}
|
||||
|
||||
.tw-modal {
|
||||
@theme {
|
||||
--animate-*: initial;
|
||||
--animate-pulse-grow: pulseGrow 2s ease-in-out infinite;
|
||||
|
||||
--z-index-500: 500;
|
||||
--z-index-1000: 1000;
|
||||
--z-index-2000: 2000;
|
||||
--z-index-3000: 3000;
|
||||
|
||||
--min-width-56: 224px;
|
||||
--min-width-64: 240px;
|
||||
--min-width-80: 320px;
|
||||
|
||||
--container-52: 208px;
|
||||
--container-64: 240px;
|
||||
--container-72: 288px;
|
||||
|
||||
--min-height-56: 224px;
|
||||
--min-height-64: 240px;
|
||||
--min-height-80: 320px;
|
||||
|
||||
--font-sans: Helvetica, sans-serif, Roboto;
|
||||
|
||||
--text-map: 13px;
|
||||
|
||||
--leading-map: 1.4em;
|
||||
|
||||
@keyframes pulseGrow {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
80% {
|
||||
transform: scale(1);
|
||||
}
|
||||
90% {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
The default border color has changed to `currentColor` in Tailwind CSS v4,
|
||||
so we've added these compatibility styles to make sure everything still
|
||||
looks the same as it did with Tailwind CSS v3.
|
||||
|
||||
If we ever want to remove these styles, we need to add an explicit border
|
||||
color utility to any element that depends on these defaults.
|
||||
*/
|
||||
@layer base {
|
||||
*,
|
||||
::after,
|
||||
::before,
|
||||
::backdrop,
|
||||
::file-selector-button {
|
||||
border-color: var(--color-gray-200, currentColor);
|
||||
}
|
||||
}
|
||||
|
||||
.modal {
|
||||
z-index: 1200 !important;
|
||||
}
|
||||
|
||||
.tw-menu li a {
|
||||
.menu li a {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.tw-modal {
|
||||
.modal {
|
||||
z-index: 1200 !important;
|
||||
max-height: 100dvh;
|
||||
}
|
||||
|
||||
.tw-modal-box {
|
||||
.modal-box {
|
||||
max-height: calc(100dvh - 2em);
|
||||
}
|
||||
|
||||
.tw-tab-content .container {
|
||||
height: 100%;
|
||||
}
|
||||
@ -1,20 +1,20 @@
|
||||
: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-color-info: var(--color-info);
|
||||
--toastify-color-success: var(--color-success);
|
||||
--toastify-color-warning: var(--color-warning);
|
||||
--toastify-color-error: var(--color-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);
|
||||
border-radius: var(--radius-box);
|
||||
--shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
||||
--shadow-colored: 0 20px 25px -5px var(--shadow-color), 0 8px 10px -6px var(--shadow-color);
|
||||
box-shadow: var(--ring-offset-shadow, 0 0 #0000), var(--ring-shadow, 0 0 #0000), var(--shadow);
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
background-color: theme('colors.base-100');
|
||||
color: theme('colors.base-content');
|
||||
background-color: var(--color-base-100);
|
||||
color: var(--color-base-content);
|
||||
}
|
||||
|
||||
.Toastify__toast-container {
|
||||
|
||||
@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="tw-w-5 tw-h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15"></path></svg>
|
||||
|
Before Width: | Height: | Size: 226 B After Width: | Height: | Size: 220 B |
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user