diff --git a/web/src/beta/components/fields/DateTimeField/index.stories.tsx b/web/src/beta/components/fields/DateTimeField/index.stories.tsx new file mode 100644 index 000000000..8d924477b --- /dev/null +++ b/web/src/beta/components/fields/DateTimeField/index.stories.tsx @@ -0,0 +1,16 @@ +import { action } from "@storybook/addon-actions"; +import { Meta, StoryObj } from "@storybook/react"; + +import DateTimeField from "."; + +const meta: Meta = { + component: DateTimeField, +}; + +export default meta; + +type Story = StoryObj; + +export const DateTimeFieldInput: Story = { + render: () => , +}; diff --git a/web/src/beta/components/fields/DateTimeField/index.tsx b/web/src/beta/components/fields/DateTimeField/index.tsx new file mode 100644 index 000000000..0be591191 --- /dev/null +++ b/web/src/beta/components/fields/DateTimeField/index.tsx @@ -0,0 +1,63 @@ +import { useCallback, useEffect, useState } from "react"; + +import { styled } from "@reearth/services/theme"; + +import Property from ".."; +import TextInput from "../common/TextInput"; + +export type Props = { + name?: string; + description?: string; + value?: string; + onChange?: (value?: string | undefined) => void; +}; + +const DateTimeField: React.FC = ({ name, description, value, onChange }) => { + const [time, setTime] = useState(); + const [date, setDate] = useState(); + + const handleTimeChange = useCallback( + (newValue: string | undefined) => { + if (newValue === undefined) return; + + setTime(newValue); + onChange?.(date + " " + newValue); + }, + [date, onChange], + ); + + const handleDateChange = useCallback( + (newValue: string | undefined) => { + if (newValue === undefined) return; + + setDate(newValue); + onChange?.(newValue + " " + time); + }, + [time, onChange], + ); + + useEffect(() => { + if (value) { + const [dateString, timeString] = value.split(" "); + setTime(timeString); + setDate(dateString); + } + }, [value]); + + return ( + + + + + + + ); +}; + +export default DateTimeField; + +const Wrapper = styled.div` + display: flex; + align-items: stretch; + gap: 4px; +`; diff --git a/web/src/beta/components/fields/PropertyFields/index.tsx b/web/src/beta/components/fields/PropertyFields/index.tsx index fbb8e767f..f187cae5f 100644 --- a/web/src/beta/components/fields/PropertyFields/index.tsx +++ b/web/src/beta/components/fields/PropertyFields/index.tsx @@ -15,6 +15,8 @@ import type { FlyTo } from "@reearth/beta/lib/core/types"; import type { Camera, LatLng } from "@reearth/beta/utils/value"; import type { Item } from "@reearth/services/api/propertyApi/utils"; +import DateTimeField from "../DateTimeField"; + import useHooks from "./hooks"; type Props = { @@ -96,7 +98,15 @@ const PropertyFields: React.FC = ({ propertyId, item, currentCamera, onFl const handleChange = handlePropertyValueUpdate(sf.id, sf.type, selected); return sf.type === "string" ? ( - sf.ui === "color" ? ( + sf.ui === "datetime" ? ( + + ) : sf.ui === "color" ? ( void; onBlur?: () => void; onExit?: (e: React.KeyboardEvent) => void; @@ -20,6 +21,7 @@ const TextInput: React.FC = ({ onChange, onBlur, onExit, + type, }) => { const [currentValue, setCurrentValue] = useState(value ?? ""); const timeoutRef = useRef(); @@ -63,6 +65,7 @@ const TextInput: React.FC = ({ return ( theme.outline.main}; } + color-scheme: dark; `; diff --git a/web/src/services/api/propertyApi/utils.ts b/web/src/services/api/propertyApi/utils.ts index 3c21c4bc0..a7ab9e39f 100644 --- a/web/src/services/api/propertyApi/utils.ts +++ b/web/src/services/api/propertyApi/utils.ts @@ -56,7 +56,8 @@ export type SchemaFieldType = { | "layer" | "cameraPose" | "padding" - | "margin"; + | "margin" + | "datetime"; choices?: { key: string; label: string;