updated dialog and calendar
This commit is contained in:
Generated
+88
@@ -12,6 +12,8 @@
|
|||||||
"@radix-ui/react-context-menu": "^2.2.6",
|
"@radix-ui/react-context-menu": "^2.2.6",
|
||||||
"@radix-ui/react-dialog": "^1.1.6",
|
"@radix-ui/react-dialog": "^1.1.6",
|
||||||
"@radix-ui/react-label": "^2.1.2",
|
"@radix-ui/react-label": "^2.1.2",
|
||||||
|
"@radix-ui/react-popover": "^1.1.6",
|
||||||
|
"@radix-ui/react-select": "^2.1.6",
|
||||||
"@radix-ui/react-separator": "^1.1.2",
|
"@radix-ui/react-separator": "^1.1.2",
|
||||||
"@radix-ui/react-slot": "^1.1.2",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
"@radix-ui/react-tabs": "^1.1.3",
|
"@radix-ui/react-tabs": "^1.1.3",
|
||||||
@@ -761,6 +763,12 @@
|
|||||||
"url": "https://opencollective.com/preact"
|
"url": "https://opencollective.com/preact"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/number": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/primitive": {
|
"node_modules/@radix-ui/primitive": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
|
||||||
@@ -1103,6 +1111,43 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-popover": {
|
||||||
|
"version": "1.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.6.tgz",
|
||||||
|
"integrity": "sha512-NQouW0x4/GnkFJ/pRqsIS3rM/k97VzKnVb2jB7Gq7VEGPy5g7uNV1ykySFt7eWSp3i2uSGFwaJcvIRJBAHmmFg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/primitive": "1.1.1",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
|
"@radix-ui/react-context": "1.1.1",
|
||||||
|
"@radix-ui/react-dismissable-layer": "1.1.5",
|
||||||
|
"@radix-ui/react-focus-guards": "1.1.1",
|
||||||
|
"@radix-ui/react-focus-scope": "1.1.2",
|
||||||
|
"@radix-ui/react-id": "1.1.0",
|
||||||
|
"@radix-ui/react-popper": "1.2.2",
|
||||||
|
"@radix-ui/react-portal": "1.1.4",
|
||||||
|
"@radix-ui/react-presence": "1.1.2",
|
||||||
|
"@radix-ui/react-primitive": "2.0.2",
|
||||||
|
"@radix-ui/react-slot": "1.1.2",
|
||||||
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||||
|
"aria-hidden": "^1.2.4",
|
||||||
|
"react-remove-scroll": "^2.6.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-popper": {
|
"node_modules/@radix-ui/react-popper": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz",
|
||||||
@@ -1237,6 +1282,49 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-select": {
|
||||||
|
"version": "2.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.6.tgz",
|
||||||
|
"integrity": "sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/number": "1.1.0",
|
||||||
|
"@radix-ui/primitive": "1.1.1",
|
||||||
|
"@radix-ui/react-collection": "1.1.2",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.1",
|
||||||
|
"@radix-ui/react-context": "1.1.1",
|
||||||
|
"@radix-ui/react-direction": "1.1.0",
|
||||||
|
"@radix-ui/react-dismissable-layer": "1.1.5",
|
||||||
|
"@radix-ui/react-focus-guards": "1.1.1",
|
||||||
|
"@radix-ui/react-focus-scope": "1.1.2",
|
||||||
|
"@radix-ui/react-id": "1.1.0",
|
||||||
|
"@radix-ui/react-popper": "1.2.2",
|
||||||
|
"@radix-ui/react-portal": "1.1.4",
|
||||||
|
"@radix-ui/react-primitive": "2.0.2",
|
||||||
|
"@radix-ui/react-slot": "1.1.2",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||||
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.0",
|
||||||
|
"@radix-ui/react-use-previous": "1.1.0",
|
||||||
|
"@radix-ui/react-visually-hidden": "1.1.2",
|
||||||
|
"aria-hidden": "^1.2.4",
|
||||||
|
"react-remove-scroll": "^2.6.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-separator": {
|
"node_modules/@radix-ui/react-separator": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.2.tgz",
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
"@radix-ui/react-context-menu": "^2.2.6",
|
"@radix-ui/react-context-menu": "^2.2.6",
|
||||||
"@radix-ui/react-dialog": "^1.1.6",
|
"@radix-ui/react-dialog": "^1.1.6",
|
||||||
"@radix-ui/react-label": "^2.1.2",
|
"@radix-ui/react-label": "^2.1.2",
|
||||||
|
"@radix-ui/react-popover": "^1.1.6",
|
||||||
|
"@radix-ui/react-select": "^2.1.6",
|
||||||
"@radix-ui/react-separator": "^1.1.2",
|
"@radix-ui/react-separator": "^1.1.2",
|
||||||
"@radix-ui/react-slot": "^1.1.2",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
"@radix-ui/react-tabs": "^1.1.3",
|
"@radix-ui/react-tabs": "^1.1.3",
|
||||||
|
|||||||
+58
-51
@@ -1,17 +1,12 @@
|
|||||||
'use client';
|
'use client';
|
||||||
import { useCalendarApp, ScheduleXCalendar } from '@schedule-x/react';
|
import { useCalendarApp, ScheduleXCalendar } from '@schedule-x/react';
|
||||||
import {
|
import { createViewWeek } from '@schedule-x/calendar';
|
||||||
createViewDay,
|
|
||||||
createViewMonthAgenda,
|
|
||||||
createViewMonthGrid,
|
|
||||||
createViewWeek,
|
|
||||||
} from '@schedule-x/calendar';
|
|
||||||
|
|
||||||
import { createEventsServicePlugin } from '@schedule-x/events-service';
|
import { createEventsServicePlugin } from '@schedule-x/events-service';
|
||||||
import { createDragAndDropPlugin } from '@schedule-x/drag-and-drop';
|
import { createDragAndDropPlugin } from '@schedule-x/drag-and-drop';
|
||||||
|
|
||||||
import '@/calendar-theme.css';
|
import '@/calendar-theme.css';
|
||||||
import { useEffect, useState } from 'react';
|
import { MouseEventHandler, useEffect, useState } from 'react';
|
||||||
import App from '@/components/app';
|
import App from '@/components/app';
|
||||||
import {
|
import {
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
@@ -21,26 +16,16 @@ import {
|
|||||||
} from '@/components/ui/context-menu';
|
} from '@/components/ui/context-menu';
|
||||||
|
|
||||||
import { PlusCircle } from 'lucide-react';
|
import { PlusCircle } from 'lucide-react';
|
||||||
import {
|
|
||||||
Dialog,
|
import { parse } from 'date-fns';
|
||||||
DialogContent,
|
import PostDialog, { today } from '@/components/postDialog';
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
} from '@/components/ui/dialog';
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
|
|
||||||
function CalendarApp() {
|
function CalendarApp() {
|
||||||
const eventsService = useState(() => createEventsServicePlugin())[0];
|
const eventsService = useState(() => createEventsServicePlugin())[0];
|
||||||
const dragAndDrop = useState(() => createDragAndDropPlugin())[0];
|
const dragAndDrop = useState(() => createDragAndDropPlugin())[0];
|
||||||
|
|
||||||
const calendar = useCalendarApp({
|
const calendar = useCalendarApp({
|
||||||
views: [
|
views: [createViewWeek()],
|
||||||
createViewDay(),
|
|
||||||
createViewWeek(),
|
|
||||||
createViewMonthGrid(),
|
|
||||||
createViewMonthAgenda(),
|
|
||||||
],
|
|
||||||
events: [
|
events: [
|
||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
@@ -58,38 +43,64 @@ function CalendarApp() {
|
|||||||
}, [eventsService]);
|
}, [eventsService]);
|
||||||
|
|
||||||
const [newPostDialogOpen, setNewPostDialogOpen] = useState(false);
|
const [newPostDialogOpen, setNewPostDialogOpen] = useState(false);
|
||||||
|
const [date, setDate] = useState<Date>(today);
|
||||||
|
|
||||||
|
const handleDialog: MouseEventHandler<HTMLSpanElement> = (event) => {
|
||||||
|
const target = event.target as HTMLElement;
|
||||||
|
|
||||||
|
let hourElement = null;
|
||||||
|
let closestDistance = Infinity;
|
||||||
|
const children = target.parentElement?.children[0].children || [];
|
||||||
|
|
||||||
|
for (let child of children) {
|
||||||
|
const childRect = child.getBoundingClientRect();
|
||||||
|
const dx = Math.abs(
|
||||||
|
event.clientX - (childRect.left + childRect.width / 2)
|
||||||
|
);
|
||||||
|
const dy = Math.abs(
|
||||||
|
event.clientY - (childRect.top + childRect.height / 2)
|
||||||
|
);
|
||||||
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
if (distance < closestDistance) {
|
||||||
|
closestDistance = distance;
|
||||||
|
hourElement = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dayElement = target.closest('.sx__time-grid-day');
|
||||||
|
|
||||||
|
const dayText = dayElement
|
||||||
|
? dayElement.getAttribute('aria-label')
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (!dayText || !hourElement) {
|
||||||
|
event.preventDefault();
|
||||||
|
} else {
|
||||||
|
setDate(
|
||||||
|
parse(
|
||||||
|
(dayText || '') + ' ' + (hourElement?.textContent || ''),
|
||||||
|
'MMMM dd, yyyy h a',
|
||||||
|
new Date()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<App>
|
<App>
|
||||||
<div>
|
<div>
|
||||||
<Dialog
|
<PostDialog
|
||||||
open={newPostDialogOpen}
|
date={date}
|
||||||
onOpenChange={setNewPostDialogOpen}
|
setDate={setDate}
|
||||||
>
|
newPostDialogOpen={newPostDialogOpen}
|
||||||
<DialogContent>
|
setNewPostDialogOpen={setNewPostDialogOpen}
|
||||||
<DialogHeader>
|
/>
|
||||||
<DialogTitle>Feature not available</DialogTitle>
|
|
||||||
</DialogHeader>
|
|
||||||
<div></div>
|
|
||||||
<DialogFooter>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => setNewPostDialogOpen(false)}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
<Button>Submit</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
|
|
||||||
<ContextMenu>
|
<ContextMenu>
|
||||||
<ContextMenuTrigger>
|
<ContextMenuTrigger onContextMenu={handleDialog}>
|
||||||
<ScheduleXCalendar
|
<ScheduleXCalendar
|
||||||
calendarApp={calendar}
|
calendarApp={calendar}
|
||||||
customComponents={{
|
customComponents={{}}
|
||||||
headerContent: CalendarHeader,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</ContextMenuTrigger>
|
</ContextMenuTrigger>
|
||||||
<ContextMenuContent>
|
<ContextMenuContent>
|
||||||
@@ -99,7 +110,7 @@ function CalendarApp() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PlusCircle className="w-4 mt-0.5" />{' '}
|
<PlusCircle className="w-4 mt-0.5" />{' '}
|
||||||
<p className="ml-1">New post</p>
|
<p className="ml-1">New post</p>x
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
</ContextMenuContent>
|
</ContextMenuContent>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
@@ -108,8 +119,4 @@ function CalendarApp() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CalendarHeader() {
|
|
||||||
return <div className="flex flex-row w-full"></div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CalendarApp;
|
export default CalendarApp;
|
||||||
|
|||||||
+39
-62
@@ -14,66 +14,43 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--sx-color-primary: #6750a4;
|
--sx-color-primary: hsl(var(--primary));
|
||||||
--sx-color-on-primary: #fff;
|
--sx-color-on-primary: hsl(var(--primary-foreground));
|
||||||
--sx-color-primary-container: #eaddff;
|
--sx-color-primary-container: hsl(var(--secondary));
|
||||||
--sx-color-on-primary-container: #21005e;
|
--sx-color-on-primary-container: hsl(var(--secondary-foreground));
|
||||||
--sx-color-secondary: #625b71;
|
|
||||||
--sx-color-on-secondary: #fff;
|
--sx-color-secondary: hsl(var(--muted));
|
||||||
--sx-color-secondary-container: #e8def8;
|
--sx-color-on-secondary: hsl(var(--muted-foreground));
|
||||||
--sx-color-on-secondary-container: #1e192b;
|
--sx-color-secondary-container: hsl(var(--accent));
|
||||||
--sx-color-tertiary: #7d5260;
|
--sx-color-on-secondary-container: hsl(var(--accent-foreground));
|
||||||
--sx-color-on-tertiary: #fff;
|
|
||||||
--sx-color-tertiary-container: #ffd8e4;
|
--sx-color-tertiary: hsl(var(--chart-1));
|
||||||
--sx-color-on-tertiary-container: #370b1e;
|
--sx-color-on-tertiary: hsl(var(--foreground));
|
||||||
--sx-color-surface: #fef7ff;
|
--sx-color-tertiary-container: hsl(var(--chart-2));
|
||||||
--sx-color-surface-dim: #ded8e1;
|
--sx-color-on-tertiary-container: hsl(var(--foreground));
|
||||||
--sx-color-surface-bright: #fef7ff;
|
|
||||||
--sx-color-on-surface: #1c1b1f;
|
--sx-color-surface: hsl(var(--background));
|
||||||
--sx-color-surface-container: #f3edf7;
|
--sx-color-surface-dim: hsl(var(--card));
|
||||||
--sx-color-surface-container-low: #f7f2fa;
|
--sx-color-surface-bright: hsl(var(--popover));
|
||||||
--sx-color-surface-container-high: #ece6f0;
|
--sx-color-on-surface: hsl(var(--foreground));
|
||||||
--sx-color-background: #fff;
|
|
||||||
--sx-color-on-background: #1c1b1f;
|
--sx-color-surface-container: hsl(var(--card));
|
||||||
--sx-color-outline: #79747e;
|
--sx-color-surface-container-low: hsl(var(--popover));
|
||||||
--sx-color-outline-variant: #c4c7c5;
|
--sx-color-surface-container-high: hsl(var(--secondary));
|
||||||
--sx-color-shadow: #000;
|
|
||||||
--sx-color-surface-tint: #6750a4;
|
--sx-color-on-background: hsl(var(--foreground));
|
||||||
--sx-color-neutral: var(--sx-color-outline);
|
--sx-color-background: hsl(var(--background));
|
||||||
--sx-color-neutral-variant: var(--sx-color-outline-variant);
|
|
||||||
--sx-internal-color-gray-ripple-background: #e0e0e0;
|
--sx-color-outline: hsl(var(--border));
|
||||||
--sx-internal-color-light-gray: #fafafa;
|
--sx-color-outline-variant: hsl(var(--input));
|
||||||
--sx-internal-color-text: #000;
|
|
||||||
|
--sx-color-shadow: hsl(var(--background));
|
||||||
|
--sx-color-surface-tint: var(--sx-color-primary);
|
||||||
|
|
||||||
|
--sx-internal-color-text: hsl(var(--foreground));
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-dark {
|
/* .is-dark {} */
|
||||||
--sx-color-primary: #d0bcff;
|
|
||||||
--sx-color-on-primary: #371e73;
|
|
||||||
--sx-color-primary-container: #4f378b;
|
|
||||||
--sx-color-on-primary-container: #eaddff;
|
|
||||||
--sx-color-secondary: #ccc2dc;
|
|
||||||
--sx-color-on-secondary: #332d41;
|
|
||||||
--sx-color-secondary-container: #4a4458;
|
|
||||||
--sx-color-on-secondary-container: #e8def8;
|
|
||||||
--sx-color-tertiary: #efb8c8;
|
|
||||||
--sx-color-on-tertiary: #492532;
|
|
||||||
--sx-color-tertiary-container: #633b48;
|
|
||||||
--sx-color-on-tertiary-container: #ffd8e4;
|
|
||||||
--sx-color-surface: #141218;
|
|
||||||
--sx-color-surface-dim: #141218;
|
|
||||||
--sx-color-surface-bright: #3b383e;
|
|
||||||
--sx-color-on-surface: #e6e1e5;
|
|
||||||
--sx-color-surface-container: #211f26;
|
|
||||||
--sx-color-surface-container-low: #1d1b20;
|
|
||||||
--sx-color-surface-container-high: #2b2930;
|
|
||||||
--sx-color-background: #141218;
|
|
||||||
--sx-color-on-background: #e6e1e5;
|
|
||||||
--sx-color-outline: #938f99;
|
|
||||||
--sx-color-outline-variant: #444746;
|
|
||||||
--sx-color-shadow: #000;
|
|
||||||
--sx-color-surface-tint: #d0bcff;
|
|
||||||
--sx-internal-color-text: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--sx-spacing-padding1: 4px;
|
--sx-spacing-padding1: 4px;
|
||||||
@@ -90,7 +67,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
--sx-rounding-extra-small: 4px;
|
--sx-rounding-extra-small: 4px;
|
||||||
--sx-rounding-small: 8px;
|
--sx-rounding-small: 8px;
|
||||||
--sx-rounding-extra-large: 28px;
|
--sx-rounding-extra-large: 28px;
|
||||||
--sx-border: 1px solid var(--sx-color-outline-variant);
|
/* --sx-border: 1px solid var(--sx-color-outline-variant); */
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-dark {
|
.is-dark {
|
||||||
@@ -497,7 +474,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
position: relative;
|
position: relative;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border: var(--sx-border);
|
/* border: var(--sx-border); */ /* Disabled this to make it look cleaner*/
|
||||||
border-radius: var(--sx-rounding-small);
|
border-radius: var(--sx-rounding-small);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
@@ -513,7 +490,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sx__slide-left {
|
.sx__slide-left {
|
||||||
animation: sx-slide-left 0.3s ease-out;
|
/* animation: sx-slide-left 0.3s ease-out; */
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes sx-slide-left {
|
@keyframes sx-slide-left {
|
||||||
@@ -529,7 +506,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sx__slide-right {
|
.sx__slide-right {
|
||||||
animation: sx-slide-right 0.3s ease-out;
|
/* animation: sx-slide-right 0.3s ease-out; */
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes sx-slide-right {
|
@keyframes sx-slide-right {
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from '@/components/ui/dialog';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from '@/components/ui/popover';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { format } from 'date-fns';
|
||||||
|
import { CalendarIcon } from 'lucide-react';
|
||||||
|
import { Calendar } from './ui/calendar';
|
||||||
|
import TimeSelect from './timeSelect';
|
||||||
|
|
||||||
|
type PostDialogProps = {
|
||||||
|
newPostDialogOpen: boolean;
|
||||||
|
setNewPostDialogOpen: (b: boolean) => void;
|
||||||
|
date: Date;
|
||||||
|
setDate: (d: Date) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const today = new Date();
|
||||||
|
today.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
export default function PostDialog({
|
||||||
|
newPostDialogOpen,
|
||||||
|
setNewPostDialogOpen,
|
||||||
|
date,
|
||||||
|
setDate,
|
||||||
|
}: PostDialogProps) {
|
||||||
|
return (
|
||||||
|
<Dialog open={newPostDialogOpen} onOpenChange={setNewPostDialogOpen}>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Feature not available</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="flex flex-row gap-4">
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant={'outline'}
|
||||||
|
className={cn(
|
||||||
|
'w-[280px] justify-start text-left font-normal',
|
||||||
|
!date && 'text-muted-foreground'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||||
|
{date ? (
|
||||||
|
format(date, 'MMMM dd y')
|
||||||
|
) : (
|
||||||
|
<span>Pick a date</span>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-auto p-0">
|
||||||
|
<Calendar
|
||||||
|
selected={date}
|
||||||
|
onSelect={(d: Date | undefined) => {
|
||||||
|
if (d) {
|
||||||
|
const newDate = new Date(d); // Clone d
|
||||||
|
newDate.setHours(
|
||||||
|
date.getHours(),
|
||||||
|
date.getMinutes(),
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
setDate(newDate);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
mode="single"
|
||||||
|
disabled={(date) => date < today}
|
||||||
|
/>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
|
||||||
|
<TimeSelect
|
||||||
|
date={date || new Date()}
|
||||||
|
setDate={setDate}
|
||||||
|
className=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DialogFooter>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setNewPostDialogOpen(false)}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button>Submit</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from '@/components/ui/popover';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from '@/components/ui/select';
|
||||||
|
|
||||||
|
interface TimeSelectProps {
|
||||||
|
date: Date;
|
||||||
|
setDate: (newDate: Date) => void;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TimeSelect: React.FC<TimeSelectProps> = ({
|
||||||
|
date,
|
||||||
|
setDate,
|
||||||
|
className,
|
||||||
|
}) => {
|
||||||
|
// Generate time options for all hours (00-23) with minutes (15, 30, 45)
|
||||||
|
const times = Array.from({ length: 24 }, (_, h) =>
|
||||||
|
[15, 30, 45].map((m) => `${h.toString().padStart(2, '0')}:${m}`)
|
||||||
|
).flat();
|
||||||
|
|
||||||
|
const currentHour = date.getHours().toString().padStart(2, '0');
|
||||||
|
const currentMinute = date.getMinutes();
|
||||||
|
const nearestMinute = [15, 30, 45].reduce((prev, curr) =>
|
||||||
|
Math.abs(curr - currentMinute) < Math.abs(prev - currentMinute)
|
||||||
|
? curr
|
||||||
|
: prev
|
||||||
|
);
|
||||||
|
const selectedTime = `${currentHour}:${nearestMinute}`;
|
||||||
|
|
||||||
|
const handleTimeChange = (newTime: string) => {
|
||||||
|
const [hour, minute] = newTime.split(':').map(Number);
|
||||||
|
const newDate = new Date(date);
|
||||||
|
newDate.setHours(hour, minute, 0, 0);
|
||||||
|
setDate(newDate);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Select onValueChange={handleTimeChange}>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue
|
||||||
|
placeholder={selectedTime}
|
||||||
|
className={className}
|
||||||
|
/>
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{times.map((t) => (
|
||||||
|
<SelectItem key={t} value={t}>
|
||||||
|
{t}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TimeSelect;
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Popover = PopoverPrimitive.Root
|
||||||
|
|
||||||
|
const PopoverTrigger = PopoverPrimitive.Trigger
|
||||||
|
|
||||||
|
const PopoverAnchor = PopoverPrimitive.Anchor
|
||||||
|
|
||||||
|
const PopoverContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||||
|
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||||
|
<PopoverPrimitive.Portal>
|
||||||
|
<PopoverPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
align={align}
|
||||||
|
sideOffset={sideOffset}
|
||||||
|
className={cn(
|
||||||
|
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</PopoverPrimitive.Portal>
|
||||||
|
))
|
||||||
|
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
||||||
|
|
||||||
|
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||||
|
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Select = SelectPrimitive.Root
|
||||||
|
|
||||||
|
const SelectGroup = SelectPrimitive.Group
|
||||||
|
|
||||||
|
const SelectValue = SelectPrimitive.Value
|
||||||
|
|
||||||
|
const SelectTrigger = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Trigger
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<SelectPrimitive.Icon asChild>
|
||||||
|
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||||
|
</SelectPrimitive.Icon>
|
||||||
|
</SelectPrimitive.Trigger>
|
||||||
|
))
|
||||||
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
||||||
|
|
||||||
|
const SelectScrollUpButton = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.ScrollUpButton
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex cursor-default items-center justify-center py-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ChevronUp className="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ScrollUpButton>
|
||||||
|
))
|
||||||
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
|
||||||
|
|
||||||
|
const SelectScrollDownButton = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.ScrollDownButton
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex cursor-default items-center justify-center py-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ChevronDown className="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ScrollDownButton>
|
||||||
|
))
|
||||||
|
SelectScrollDownButton.displayName =
|
||||||
|
SelectPrimitive.ScrollDownButton.displayName
|
||||||
|
|
||||||
|
const SelectContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||||
|
>(({ className, children, position = "popper", ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Portal>
|
||||||
|
<SelectPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
|
position === "popper" &&
|
||||||
|
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
position={position}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<SelectScrollUpButton />
|
||||||
|
<SelectPrimitive.Viewport
|
||||||
|
className={cn(
|
||||||
|
"p-1",
|
||||||
|
position === "popper" &&
|
||||||
|
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</SelectPrimitive.Viewport>
|
||||||
|
<SelectScrollDownButton />
|
||||||
|
</SelectPrimitive.Content>
|
||||||
|
</SelectPrimitive.Portal>
|
||||||
|
))
|
||||||
|
SelectContent.displayName = SelectPrimitive.Content.displayName
|
||||||
|
|
||||||
|
const SelectLabel = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Label
|
||||||
|
ref={ref}
|
||||||
|
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
||||||
|
|
||||||
|
const SelectItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Item
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<SelectPrimitive.ItemIndicator>
|
||||||
|
<Check className="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ItemIndicator>
|
||||||
|
</span>
|
||||||
|
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||||
|
</SelectPrimitive.Item>
|
||||||
|
))
|
||||||
|
SelectItem.displayName = SelectPrimitive.Item.displayName
|
||||||
|
|
||||||
|
const SelectSeparator = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Separator
|
||||||
|
ref={ref}
|
||||||
|
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
||||||
|
|
||||||
|
export {
|
||||||
|
Select,
|
||||||
|
SelectGroup,
|
||||||
|
SelectValue,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectContent,
|
||||||
|
SelectLabel,
|
||||||
|
SelectItem,
|
||||||
|
SelectSeparator,
|
||||||
|
SelectScrollUpButton,
|
||||||
|
SelectScrollDownButton,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user