diff --git a/src/App.css b/src/App.css
index 624192b..f05b2b1 100644
--- a/src/App.css
+++ b/src/App.css
@@ -166,7 +166,13 @@ input[type="checkbox"] {
.margin-0 {
margin: 0;
}
+.margin-lg {
+ margin: 1rem;
+}
+.padding-0 {
+ padding: 0;
+}
.padding-sm {
padding: .25rem;
}
@@ -176,11 +182,9 @@ input[type="checkbox"] {
.padding-lg {
padding: 1rem;
}
-.padding-b-sm {
- padding-bottom: .25rem;
-}
-.padding-b-md {
- padding-bottom: .5rem;
+.padding-h-lg {
+ padding-left: 1rem;
+ padding-right: 1rem;
}
.padding-b-lg {
padding-bottom: 1rem;
@@ -209,6 +213,27 @@ input[type="checkbox"] {
border: 3px solid canvastext;
}
+.shadow-sm {
+ box-shadow: 0 0 0.25rem rgba(0, 0, 0, 0.25);
+}
+.shadow-md {
+ box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.25);
+}
+.shadow-lg {
+ box-shadow: 0 0 1rem rgba(0, 0, 0, 0.25);
+}
+@media (prefers-color-scheme: dark) {
+ .shadow-sm {
+ box-shadow: 0 0 0.25rem rgba(0, 0, 0, 0.5);
+ }
+ .shadow-md {
+ box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.5);
+ }
+ .shadow-lg {
+ box-shadow: 0 0 1rem rgba(0, 0, 0, 0.5);
+ }
+}
+
.font-small {
font-size: .75rem;
}
@@ -225,6 +250,9 @@ input[type="checkbox"] {
font-weight: bold;
}
+.relative {
+ position: relative;
+}
.clickable {
cursor: pointer;
diff --git a/src/App.tsx b/src/App.tsx
index 25c9468..c9ac2d7 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -19,7 +19,7 @@ function App(){
© Utrecht University (ICS)
Home
-
+
diff --git a/src/components/Dialog.tsx b/src/components/Dialog.tsx
new file mode 100644
index 0000000..093f0a4
--- /dev/null
+++ b/src/components/Dialog.tsx
@@ -0,0 +1,48 @@
+import {type ReactNode, type RefObject, useEffect, useRef} from "react";
+
+export default function Dialog({
+ open,
+ close,
+ classname,
+ children,
+}: {
+ open: boolean;
+ close: () => void;
+ classname?: string;
+ children: ReactNode;
+}) {
+ const ref: RefObject = useRef(null);
+
+ useEffect(() => {
+ if (open) {
+ ref.current?.showModal();
+ } else {
+ ref.current?.close();
+ }
+ }, [open]);
+
+ function handleClickOutside(event: React.MouseEvent) {
+ if (!ref.current) return;
+
+ const dialogDimensions = ref.current.getBoundingClientRect()
+ if (
+ event.clientX < dialogDimensions.left ||
+ event.clientX > dialogDimensions.right ||
+ event.clientY < dialogDimensions.top ||
+ event.clientY > dialogDimensions.bottom
+ ) {
+ close();
+ }
+ }
+
+ return (
+
+ );
+}
diff --git a/src/components/Icons/Next.tsx b/src/components/Icons/Next.tsx
new file mode 100644
index 0000000..1d30937
--- /dev/null
+++ b/src/components/Icons/Next.tsx
@@ -0,0 +1,5 @@
+export default function Next({ fill }: { fill?: string }) {
+ return ;
+}
\ No newline at end of file
diff --git a/src/components/Icons/Pause.tsx b/src/components/Icons/Pause.tsx
new file mode 100644
index 0000000..dcf5e08
--- /dev/null
+++ b/src/components/Icons/Pause.tsx
@@ -0,0 +1,5 @@
+export default function Pause({ fill }: { fill?: string }) {
+ return ;
+}
diff --git a/src/components/Icons/Play.tsx b/src/components/Icons/Play.tsx
new file mode 100644
index 0000000..3f0fb6b
--- /dev/null
+++ b/src/components/Icons/Play.tsx
@@ -0,0 +1,5 @@
+export default function Play({ fill }: { fill?: string }) {
+ return ;
+}
diff --git a/src/components/Icons/Redo.tsx b/src/components/Icons/Redo.tsx
new file mode 100644
index 0000000..4268fc5
--- /dev/null
+++ b/src/components/Icons/Redo.tsx
@@ -0,0 +1,5 @@
+export default function Redo({ fill }: { fill?: string }) {
+ return ;
+}
\ No newline at end of file
diff --git a/src/components/Icons/Replay.tsx b/src/components/Icons/Replay.tsx
new file mode 100644
index 0000000..057d4b4
--- /dev/null
+++ b/src/components/Icons/Replay.tsx
@@ -0,0 +1,5 @@
+export default function Replay({ fill }: { fill?: string }) {
+ return ;
+}
diff --git a/src/components/Logging/Definitions.ts b/src/components/Logging/Definitions.ts
new file mode 100644
index 0000000..a870301
--- /dev/null
+++ b/src/components/Logging/Definitions.ts
@@ -0,0 +1,31 @@
+import type {Cell} from "../../utils/cellStore.ts";
+import type {LogRecord} from "./useLogs.ts";
+
+/**
+ * Zustand store definition for managing user preferences related to logging.
+ *
+ * Includes flags for toggling relative timestamps and automatic scroll behavior.
+ */
+export type LoggingSettings = {
+ /** Whether to display log timestamps as relative (e.g., "2m 15s ago") instead of absolute. */
+ showRelativeTime: boolean;
+ /** Updates the `showRelativeTime` setting. */
+ setShowRelativeTime: (showRelativeTime: boolean) => void;
+};
+
+/**
+ * Props for any component that renders a single log message entry.
+ *
+ * @param recordCell - A reactive `Cell` containing a single `LogRecord`.
+ * @param onUpdate - Optional callback triggered when the log entry updates.
+ */
+export type MessageComponentProps = {
+ recordCell: Cell,
+ onUpdate?: () => void,
+};
+
+/**
+ * Key used for the experiment filter predicate in the filter map, to exclude experiment logs from the developer logs.
+ */
+export const EXPERIMENT_FILTER_KEY = "experiment_filter";
+export const EXPERIMENT_LOGGER_NAME = "experiment";
diff --git a/src/components/Logging/Filters.tsx b/src/components/Logging/Filters.tsx
index acf30fc..9b4f611 100644
--- a/src/components/Logging/Filters.tsx
+++ b/src/components/Logging/Filters.tsx
@@ -16,9 +16,8 @@ type Setter = (value: T | ((prev: T) => T)) => void;
* Mapping of log level names to their corresponding numeric severity.
* Used for comparison in log filtering predicates.
*/
-const optionMapping = new Map([
+const optionMapping: Map = new Map([
["ALL", 0],
- ["LLM", 9],
["DEBUG", 10],
["INFO", 20],
["WARNING", 30],
@@ -96,7 +95,7 @@ function GlobalLevelFilter({
filterPredicates: Map;
setFilterPredicates: Setter