+
diff --git a/frontend/src/components/Topbar.tsx b/frontend/src/components/Topbar.tsx
deleted file mode 100644
index ccf897f..0000000
--- a/frontend/src/components/Topbar.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import { Menu, X } from 'lucide-react';
-import { login, logout } from "../utils/api/users.ts";
-import { Dropdown, DropdownItem } from "./Dropdown.tsx";
-import { GoogleLogin } from '@react-oauth/google';
-
-import type { User } from "../utils/types.ts";
-import type { CredentialResponse } from '@react-oauth/google';
-
-import MenuButton from "./buttons/MenuButton.tsx";
-import clsx from "clsx";
-import {useNavigate} from "react-router-dom";
-
-
-type props = {
- sidebarToggled: boolean;
- setSidebarToggled: (toggled: boolean) => void;
- user: User | null;
- fetchUser: () => void;
- isStreaming: boolean;
- className?: string;
-}
-
-const Topbar = ({
- sidebarToggled,
- setSidebarToggled,
- user,
- fetchUser,
- isStreaming,
- className}: props) => {
-
- const navigate = useNavigate();
-
- const handleLogin = (response: CredentialResponse) => {
- if (!response.credential) {
- console.error("No credential received from Google login.");
- return;
- }
-
- login(response.credential)
- .then(() => {
- fetchUser();
- navigate(0);
- })
- .catch((error) => {
- console.error("Login failed:", error);
- });
- }
-
- const handleLogout = () => {
- logout()
- .then(() => {
- fetchUser();
- navigate("/");
- })
- .catch((error) => {
- console.error("Logout failed:", error);
- });
- }
-
- return (
-
-
setSidebarToggled(!sidebarToggled)}>
- {sidebarToggled ?
-
- { user ? (
-
-

-
-
- {user.name}
- {isStreaming && (
-
-
-
-
- )}
-
- }>
- navigate("/profile")} />
- handleLogout()}
- className={"text-red-500 font-medium"} />
-
-
- ) :
- (
-
handleLogin(credentialResponse)} />
- )}
-
- )
-}
-
-export default Topbar;
\ No newline at end of file
diff --git a/frontend/src/components/buttons/MenuButton.tsx b/frontend/src/components/buttons/MenuButton.tsx
index f1717ef..eba154c 100644
--- a/frontend/src/components/buttons/MenuButton.tsx
+++ b/frontend/src/components/buttons/MenuButton.tsx
@@ -6,7 +6,7 @@ type Props = React.ButtonHTMLAttributes
;
const MenuButton: React.FC = ({ className = "", ...props }) => {
return (
);
diff --git a/frontend/src/components/buttons/SidebarButton.tsx b/frontend/src/components/buttons/SidebarButton.tsx
index 8c5d55f..d62005c 100644
--- a/frontend/src/components/buttons/SidebarButton.tsx
+++ b/frontend/src/components/buttons/SidebarButton.tsx
@@ -13,7 +13,11 @@ const SidebarButton = ({url, logo, label}: Props) => {
return (
-
+
{logo}{label}
diff --git a/frontend/src/index.css b/frontend/src/index.css
index 4ee4c77..428c9e2 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -2,25 +2,23 @@
@plugin "flowbite-react/plugin/tailwindcss";
@theme {
+ /* Fonts */
--font-heading: "Newsreader", serif;
--font-body: "IBM Plex Sans", sans-serif;
--font-data: "IBM Plex Mono", monospace;
- /* Breakpoints */
- --breakpoint-3xl: 1920px;
+ /* Colours */
+ --color-background: #F7F4EE;
+ --color-sidebar: #F2EEE6;
+ --color-card: #FDFBF7;
- --color-primary: oklch(0.55 0.21 254);
- --color-primary-pressed: oklch(0.45 0.21 254);
- --color-secondary: oklch(0.94 0.01 250);
- --color-accent: oklch(0.68 0.20 288);
- --color-text: oklch(0.17 0.01 270);
- --color-background: oklch(0.97 0.005 250);
- --color-surface: oklch(1 0 0);
- --color-border: oklch(0.91 0.008 250);
-
- /* Easing */
- --ease-fluid: cubic-bezier(0.3, 0, 0, 1);
- --ease-snappy: cubic-bezier(0.2, 0, 0, 1);
+ /* Colour Fonts */
+ --color-text-primary: #2B2620;
+ --color-text-strong: #35302A;
+ --color-faint-mono: #A79C8E;
+ --color-muted: #9A9084;
+ --color-hover: #E7E0D2;
+ --color-hairline: #F0EBE2;
}
:root {
@@ -35,12 +33,4 @@
body {
background-color: var(--color-background);
-}
-
-#range-slider .range-slider__range {
- background: var(--color-primary);
-}
-
-#range-slider .range-slider__thumb {
- background: var(--color-primary);
}
\ No newline at end of file
diff --git a/frontend/src/layouts/MainLayout.tsx b/frontend/src/layouts/MainLayout.tsx
index 6ba6821..d78a1dc 100644
--- a/frontend/src/layouts/MainLayout.tsx
+++ b/frontend/src/layouts/MainLayout.tsx
@@ -1,50 +1,15 @@
// layout/MainLayout.jsx
import Sidebar from '../components/Sidebar'
-import Topbar from '../components/Topbar'
import { Outlet } from 'react-router-dom';
-import {useEffect, useState} from "react";
-import type {User} from "../utils/types";
-import { getUser } from "../utils/api/users";
-import { getStreamStatus } from "../utils/api/stream";
+import { useState } from "react";
const MainLayout = () => {
- const [sidebarToggled, setSidebarToggled] = useState(false);
- const [user, setUser] = useState(null);
- const [isStreaming, setIsStreaming] = useState(false);
-
- const fetchUser = async () => {
- try {
- const userData = await getUser();
- setUser(userData);
- } catch (error) {
- console.error('Failed to fetch user:', error);
- }
- };
-
- useEffect(() => {
- fetchUser();
- }, []);
-
- useEffect(() => {
- if (!user) return;
- const poll = () => getStreamStatus().then(setIsStreaming).catch(() => {});
- poll();
- const interval = setInterval(poll, 10000);
- return () => clearInterval(interval);
- }, [user]);
+ const [sidebarToggled] = useState(false);
return (
-
diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx
index 2d6958f..5054c75 100644
--- a/frontend/src/main.tsx
+++ b/frontend/src/main.tsx
@@ -2,9 +2,12 @@ import './index.css'
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
+import {AuthProvider} from "./utils/AuthContext.tsx";
createRoot(document.getElementById('root')!).render(
-
+
+
+
,
)
diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx
index 6f4ada7..9588864 100644
--- a/frontend/src/pages/Home.tsx
+++ b/frontend/src/pages/Home.tsx
@@ -1,78 +1,15 @@
-import { Upload, Scissors, SlidersHorizontal, Radio, LayoutGrid, Play } from "lucide-react";
-
-const features = [
- {
- icon: Upload,
- title: "Upload & compress",
- description: "Drop in a video file, set your clip range and export settings, then compress.",
- },
- {
- icon: Scissors,
- title: "Trim",
- description: "Set start and end points with a range slider. Preview as you go.",
- },
- {
- icon: SlidersHorizontal,
- title: "Export settings",
- description: "Choose resolution, frame rate, and an optional file size cap.",
- },
- {
- icon: Radio,
- title: "RTMP streaming",
- description: "Point OBS at your stream key and go live. Find the key in your profile.",
- },
- {
- icon: LayoutGrid,
- title: "Clip library",
- description: "Browse all your clips. Watch, rename, edit the description, or delete.",
- },
- {
- icon: Play,
- title: "Built-in player",
- description: "Scrub, adjust volume, go fullscreen. Runs in the browser.",
- },
-];
-
const Home = () => {
+ const now = new Date();
+
+ const formatted: string = new Intl.DateTimeFormat('en-IE', {
+ weekday: 'short',
+ day: 'numeric',
+ month: 'short',
+ }).format(now);
+
return (
- {/* Hero */}
-
-

-
- A home for your clips.
-
-
- Upload, trim, and export video clips. Stream live if you need to.
-
-
-
- {/* Feature grid */}
-
- {features.map(({ icon: Icon, title, description }) => (
-
-
-
-
-
-
{title}
-
{description}
-
-
- ))}
-
-
- {/* Format note */}
-
- Supports MP4, MOV, WebM, and OGG.
-
+
{formatted}
);
};
diff --git a/frontend/src/utils/AuthContext.tsx b/frontend/src/utils/AuthContext.tsx
new file mode 100644
index 0000000..a9c7ecf
--- /dev/null
+++ b/frontend/src/utils/AuthContext.tsx
@@ -0,0 +1,42 @@
+import React, {createContext, useContext, useState, useEffect, type ReactNode} from 'react';
+import { getUser } from "./api/users.ts";
+import type {User} from "./types.ts";
+
+// for what the Auth object will look like
+interface AuthContextValue {
+ user: User | null;
+ setUser: React.Dispatch>;
+ loading: boolean;
+}
+
+interface AuthProviderProps {
+ children: ReactNode;
+}
+
+const AuthContext = createContext(undefined);
+
+export function AuthProvider({children}: AuthProviderProps) {
+ const [user, setUser] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ getUser()
+ .then(setUser)
+ .catch(() => setUser(null))
+ .finally(() => setLoading(false));
+ }, []);
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function useAuth(): AuthContextValue {
+ const context = useContext(AuthContext);
+ if (context === undefined) {
+ throw new Error('useAuth must be used within an AuthProvider');
+ }
+ return context;
+}
\ No newline at end of file