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:
Anton Tranelis 2025-04-25 15:03:42 +01:00 committed by GitHub
parent 67a5e6e22d
commit 9e6bcf1846
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
104 changed files with 1716 additions and 1651 deletions

1332
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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",

View File

@ -1,7 +1,6 @@
// eslint-disable-next-line import/no-commonjs
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
'@tailwindcss/postcss': {},
},
}

View File

@ -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',

View File

@ -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>

View File

@ -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>

View File

@ -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}
>

View File

@ -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>
</>
)

View File

@ -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()}
/>

View 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>
)}
</>
)
}

View File

@ -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: '',
}

View 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])
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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 &gt;</button> */}{' '}
{/** <button className='tw:btn tw:btn-xs tw:btn-neutral tw:w-fit tw:self-center tw:mt-1'>Next &gt;</button> */}{' '}
</div>
</div>
) : (

View File

@ -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)}>

View File

@ -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}
>

View File

@ -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>

View File

@ -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', () => {

View File

@ -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>
)

View File

@ -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"

View File

@ -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=""
/>

View File

@ -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"

View File

@ -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>

View File

@ -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>

View File

@ -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>
)}

View File

@ -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>

View File

@ -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)
}}

View File

@ -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'}` }}
/>
)}

View File

@ -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>
)}

View File

@ -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>

View File

@ -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>
</>
)

View File

@ -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)}
>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>
)
}

View File

@ -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'

View File

@ -23,7 +23,7 @@ export const PopupTextInput = ({
placeholder={placeholder}
inputStyle={style}
type='text'
containerStyle={'tw-mt-4'}
containerStyle={'tw:mt-4'}
></TextInput>
)
}

View File

@ -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() : ''}

View File

@ -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,

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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 />

View File

@ -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

View File

@ -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}

View File

@ -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)

View File

@ -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)

View File

@ -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>
)}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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&nbsp;Collective</span>
on <span className='tw:font-bold'>Open&nbsp;Collective</span>
</div>
</div>
</div>

View File

@ -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>
)

View File

@ -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}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>
)}

View File

@ -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>
)

View File

@ -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>

View File

@ -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>

View File

@ -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>
)

View File

@ -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>

View File

@ -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>
)
}

View File

@ -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)}
>

View File

@ -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>

View File

@ -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>
)
},
)}

View File

@ -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>

View File

@ -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} */}

View File

@ -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'
/>
)
}

View File

@ -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>
)

View File

@ -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>
)
}

View File

@ -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>

View File

@ -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()}
>

View File

@ -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>

View File

@ -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>

View File

@ -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>
)
}

View File

@ -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}
>

View File

@ -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>

View File

@ -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>

View File

@ -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()}
>

View File

@ -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}`)}

View File

@ -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>

View File

@ -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>

View File

@ -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>
)
}

View 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>
)
}

View File

@ -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>
)
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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%;
}

View File

@ -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%;
}

View File

@ -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 {

View File

@ -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