diff --git a/web/package-lock.json b/web/package-lock.json
index 98e65710a..856923f2b 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -5320,11 +5320,6 @@
"integrity": "sha512-9YLIBURXj4DJMFALxXw9K3Y3rwb5Fk0X5/8ipCzaN84+gKxoHK43tVKRNakCQbiEx07E8Uwhuq21BpUagFhZ8w==",
"dev": true
},
- "desandro-matches-selector": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/desandro-matches-selector/-/desandro-matches-selector-2.0.2.tgz",
- "integrity": "sha1-cXvu1NwT59jzdi9wem1YpndCGOE="
- },
"detect-newline": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
@@ -6087,11 +6082,6 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
- "ev-emitter": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ev-emitter/-/ev-emitter-1.1.1.tgz",
- "integrity": "sha512-ipiDYhdQSCZ4hSbX4rMW+XzNKMD1prg/sTvoVmSLkuQ1MVlwjJQQA+sW8tMYR3BLUr9KjodFV4pvzunvRhd33Q=="
- },
"exec-sh": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz",
@@ -6381,14 +6371,6 @@
"path-exists": "^4.0.0"
}
},
- "fizzy-ui-utils": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/fizzy-ui-utils/-/fizzy-ui-utils-2.0.7.tgz",
- "integrity": "sha512-CZXDVXQ1If3/r8s0T+v+qVeMshhfcuq0rqIFgJnrtd+Bu8GmDmqMjntjUePypVtjHXKJ6V4sw9zeyox34n9aCg==",
- "requires": {
- "desandro-matches-selector": "^2.0.0"
- }
- },
"flat-cache": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
@@ -6405,19 +6387,6 @@
"integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==",
"dev": true
},
- "flickity": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/flickity/-/flickity-2.2.2.tgz",
- "integrity": "sha512-yiPMuP8tw/zN7ARgeSLZNvzK11GkzI2mp/zlYBsyttguSCROAqxj6wiN2sSfPfW3xMG3hcUHxWUXNQMlk/wYcg==",
- "requires": {
- "desandro-matches-selector": "^2.0.0",
- "ev-emitter": "^1.1.1",
- "fizzy-ui-utils": "^2.0.7",
- "get-size": "^2.0.3",
- "unidragger": "^2.3.0",
- "unipointer": "^2.3.0"
- }
- },
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -6528,11 +6497,6 @@
"integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
"dev": true
},
- "get-size": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/get-size/-/get-size-2.0.3.tgz",
- "integrity": "sha512-lXNzT/h/dTjTxRbm9BXb+SGxxzkm97h/PCIKtlN/CBCxxmkkIVV21udumMS93MuVTDX583gqc94v3RjuHmI+2Q=="
- },
"get-stdin": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
@@ -11789,14 +11753,6 @@
"integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==",
"dev": true
},
- "unidragger": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/unidragger/-/unidragger-2.3.1.tgz",
- "integrity": "sha512-u+IgG7AG0MXJTKcdzAIYxCm+W5FcnA9M28203Awl6jIcE3/+9OtEyUX4Wv64y7XNKEVRKPot52IV4V6x7FlF5Q==",
- "requires": {
- "unipointer": "^2.3.0"
- }
- },
"union-value": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
@@ -11809,14 +11765,6 @@
"set-value": "^2.0.1"
}
},
- "unipointer": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/unipointer/-/unipointer-2.3.0.tgz",
- "integrity": "sha512-m85sAoELCZhogI1owtJV3Dva7GxkHk2lI7A0otw3o0OwCuC/Q9gi7ehddigEYIAYbhkqNdri+dU1QQkrcBvirQ==",
- "requires": {
- "ev-emitter": "^1.0.1"
- }
- },
"uniq": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
diff --git a/web/package.json b/web/package.json
index 55d9edd08..7f3d8f766 100644
--- a/web/package.json
+++ b/web/package.json
@@ -12,7 +12,6 @@
},
"dependencies": {
"date-fns": "^2.21.3",
- "flickity": "^2.2.2",
"idb-keyval": "^5.0.2",
"immer": "^8.0.1",
"preact": "^10.5.9",
diff --git a/web/src/components/Accordion.jsx b/web/src/components/Accordion.jsx
new file mode 100644
index 000000000..ed63de59e
--- /dev/null
+++ b/web/src/components/Accordion.jsx
@@ -0,0 +1,20 @@
+import { h } from 'preact';
+import { useState } from 'preact/hooks';
+import ArrowDropdown from '../icons/ArrowDropdown';
+import ArrowDropup from '../icons/ArrowDropup';
+
+export default function Accordion({ title, children, selected = false }) {
+ const [active, setActive] = useState(selected);
+ const toggle = () => setActive(!active);
+ return (
+
+ );
+}
diff --git a/web/src/components/Carousel.jsx b/web/src/components/Carousel.jsx
deleted file mode 100644
index ff0682c48..000000000
--- a/web/src/components/Carousel.jsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import { h, Component } from 'preact';
-import Flickity from 'flickity';
-import 'flickity/css/flickity.css';
-
-export default class Carousel extends Component {
- constructor(props) {
- super(props);
-
- this.carousel = null;
- this.flkty = null;
- }
-
- create() {
- if (this.carousel) {
- this.flkty = new Flickity(this.carousel, this.props.options);
-
- if (this.props.flickityRef) {
- this.props.flickityRef(this.flkty);
- }
- }
- }
-
- destroy() {
- if (this.flkty) {
- this.flkty.destroy();
- this.flkty = null;
- this.carousel = null;
- }
- }
-
- componentWillUpdate() {
- this.destroy();
- }
-
- componentDidUpdate() {
- this.create();
- }
-
- componentWillUnmount() {
- this.destroy();
- }
-
- componentDidMount() {
- this.create();
- }
-
- render(props) {
- return h(
- this.props.elementType,
- {
- className: this.props.className,
- ref: (c) => {
- this.carousel = c;
- },
- },
- this.props.children
- );
- }
-}
-
-Carousel.defaultProps = {
- options: {},
- className: '',
- elementType: 'div',
-};
diff --git a/web/src/components/RecordingPlaylist.jsx b/web/src/components/RecordingPlaylist.jsx
new file mode 100644
index 000000000..466d2f47a
--- /dev/null
+++ b/web/src/components/RecordingPlaylist.jsx
@@ -0,0 +1,53 @@
+import { h } from 'preact';
+import { useState } from 'preact/hooks';
+import { format, parseISO } from 'date-fns';
+import Accordion from '../components/Accordion';
+import Link from '../components/Link';
+import Menu from '../icons/Menu';
+import MenuOpen from '../icons/MenuOpen';
+
+export default function RecordingPlaylist({ camera, recordings, selectedDate }) {
+ const [active, setActive] = useState(true);
+ const toggle = () => setActive(!active);
+
+ const result = [];
+ for (const recording of recordings.slice().reverse()) {
+ const date = parseISO(recording.date);
+ result.push(
+
+ {recording.recordings.map((item) => (
+
+
+ {item.hour}:00
+
+ {item.events} Events
+
+ ))}
+
+ );
+ }
+
+ const openClass = active ? '-left-6' : 'right-0';
+
+ return (
+
+
+ {active ?
: }
+
+
+ {result}
+
+
+ );
+}
+
+export function Heading({ title }) {
+ return {title}
;
+}
diff --git a/web/src/components/VideoPlayer.jsx b/web/src/components/VideoPlayer.jsx
index b21a9e012..2bfc63219 100644
--- a/web/src/components/VideoPlayer.jsx
+++ b/web/src/components/VideoPlayer.jsx
@@ -31,12 +31,12 @@ export default class VideoPlayer extends Component {
}
render() {
- const { style } = this.props;
+ const { style, children } = this.props;
return (
-
);
diff --git a/web/src/index.css b/web/src/index.css
index d55a9aabc..7f11122a0 100644
--- a/web/src/index.css
+++ b/web/src/index.css
@@ -25,3 +25,11 @@
transform: rotate(360deg);
}
}
+
+.vjs-playlist-modal {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 33%;
+ height: 100%;
+}
diff --git a/web/src/routes/Recording.jsx b/web/src/routes/Recording.jsx
index e1cb77a7a..2ffcba6fe 100644
--- a/web/src/routes/Recording.jsx
+++ b/web/src/routes/Recording.jsx
@@ -1,11 +1,8 @@
import { h } from 'preact';
-import { Link } from 'preact-router/match';
-import { closestTo, format, isEqual, parseISO } from 'date-fns';
+import { closestTo, format, parseISO } from 'date-fns';
import ActivityIndicator from '../components/ActivityIndicator';
-import Button from '../components/Button';
-import Calendar from '../components/Calendar';
-import Carousel from '../components/Carousel';
import Heading from '../components/Heading';
+import RecordingPlaylist from '../components/RecordingPlaylist';
import VideoPlayer from '../components/VideoPlayer';
import { FetchStatus, useApiHost, useRecording } from '../api';
@@ -24,32 +21,12 @@ export default function Recording({ camera, date, hour }) {
);
const selectedKey = format(selectedDate, 'yyyy-MM-dd');
const [year, month, day] = selectedKey.split('-');
- const calendar = [];
- const buttons = [];
const playlist = [];
const hours = [];
for (const item of data) {
- const date = parseISO(item.date);
- const events = item.recordings.map((i) => i.events);
- calendar.push(
-
- a + b)}
- selected={isEqual(selectedDate, date)}
- />
-
- );
-
if (item.date === selectedKey) {
for (const recording of item.recordings) {
- buttons.push(
-
- );
playlist.push({
name: `${selectedKey} ${recording.hour}:00`,
description: `${camera} recording @ ${recording.hour}:00.`,
@@ -76,24 +53,11 @@ export default function Recording({ camera, date, hour }) {
}
}
- const selectDate = (flkty) => {
- flkty.select(recordingDates.indexOf(selectedKey), false, true);
- };
-
- const selectHour = (flkty) => {
- flkty.select(selectedHour, false, true);
- };
-
return (
{camera} Recordings
-
- {calendar}
-
-
{
if (player.playlist) {
player.playlist(playlist);
@@ -104,11 +68,9 @@ export default function Recording({ camera, date, hour }) {
this.player = player;
}
}}
- />
-
-
- {buttons}
-
+ >
+
+
);
}