fix build warnings from tailwind, fonts, and fast refresh (#24359)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s

fix duplicated styles, move fonts to src/assets/fonts for vite to bundle (nginx already rewrites correctly), and fix fast refresh for PreviewController, auth context/provider, and statusbar context
This commit is contained in:
Josh Hawkins
2026-09-15 15:33:09 -06:00
committed by GitHub
parent cabdffea20
commit 79ca18d439
40 changed files with 112 additions and 115 deletions
@@ -343,13 +343,6 @@ http {
add_header Cache-Control "public";
}
location /fonts/ {
access_log off;
expires 1y;
include security_headers.conf;
add_header Cache-Control "public";
}
location /locales/ {
access_log off;
include security_headers.conf;
+1 -1
View File
@@ -2,7 +2,7 @@ import { useEmbeddingsReindexProgress } from "@/api/ws";
import {
StatusBarMessagesContext,
StatusMessage,
} from "@/context/statusbar-provider";
} from "@/context/statusbar-context";
import useStats, { useAutoFrigateStats } from "@/hooks/use-stats";
import StatusBarNotices from "@/components/health/StatusBarNotices";
import { cn } from "@/lib/utils";
@@ -10,7 +10,7 @@ import {
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
import { StatusBarMessagesContext } from "@/context/statusbar-context";
import { FrigateConfig } from "@/types/frigateConfig";
import { zodResolver } from "@hookform/resolvers/zod";
import axios from "axios";
@@ -61,7 +61,7 @@ import {
JsonValue,
} from "@/types/configForm";
import ActivityIndicator from "@/components/indicators/activity-indicator";
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
import { StatusBarMessagesContext } from "@/context/statusbar-context";
import {
cameraUpdateTopicMap,
globalCameraDefaultSections,
+1 -1
View File
@@ -19,7 +19,7 @@ import useNavigation from "@/hooks/use-navigation";
import {
StatusBarMessagesContext,
StatusMessage,
} from "@/context/statusbar-provider";
} from "@/context/statusbar-context";
import { Link } from "react-router-dom";
import { cn } from "@/lib/utils";
import { isMobile } from "react-device-detect";
@@ -0,0 +1,13 @@
export abstract class PreviewController {
public camera = "";
constructor(camera: string) {
this.camera = camera;
}
abstract scrubToTimestamp(time: number): boolean;
abstract finishedSeeking(): void;
abstract setNewPreviewStartTime(time: number): void;
}
+1 -14
View File
@@ -22,6 +22,7 @@ import {
} from "@/hooks/use-camera-previews";
import { useTranslation } from "react-i18next";
import { useCameraFriendlyName } from "@/hooks/use-camera-friendly-name";
import { PreviewController } from "./PreviewController";
type PreviewPlayerProps = {
previewRef?: (ref: HTMLDivElement | null) => void;
@@ -102,20 +103,6 @@ export default function PreviewPlayer({
);
}
export abstract class PreviewController {
public camera = "";
constructor(camera: string) {
this.camera = camera;
}
abstract scrubToTimestamp(time: number): boolean;
abstract finishedSeeking(): void;
abstract setNewPreviewStartTime(time: number): void;
}
type PreviewVideoPlayerProps = {
visibilityRef?: (ref: HTMLDivElement | null) => void;
className?: string;
@@ -1,6 +1,6 @@
import { Recording } from "@/types/record";
import { DynamicPlayback } from "@/types/playback";
import { PreviewController } from "../PreviewPlayer";
import { PreviewController } from "../PreviewController";
import { TimeRange, TrackingDetailsSequence } from "@/types/timeline";
import {
calculateInpointOffset,
@@ -16,7 +16,8 @@ import {
RecordingCoverage,
} from "@/types/record";
import { Preview } from "@/types/preview";
import PreviewPlayer, { PreviewController } from "../PreviewPlayer";
import PreviewPlayer from "../PreviewPlayer";
import { PreviewController } from "../PreviewController";
import { DynamicVideoController } from "./DynamicVideoController";
import HlsVideoPlayer, { HlsSource } from "../HlsVideoPlayer";
import { useDetailStream } from "@/context/detail-stream-context";
@@ -65,7 +65,7 @@ import {
import { buildConfigDataForPath } from "@/utils/configUtil";
import { useConfigSchema } from "@/hooks/use-config-schema";
import { useRestart } from "@/api/ws";
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
import { StatusBarMessagesContext } from "@/context/statusbar-context";
import RestartDialog from "@/components/overlay/dialog/RestartDialog";
import ActivityIndicator from "@/components/indicators/activity-indicator";
import SaveAllPreviewPopover from "@/components/overlay/detail/SaveAllPreviewPopover";
@@ -99,7 +99,11 @@ export default function AnimatedCircularProgressBar({
</svg>
<span
data-current-value={currentPercent}
className="duration-[var(--transition-length)] delay-[var(--delay)] absolute inset-0 m-auto size-fit ease-linear animate-in fade-in"
className="absolute inset-0 m-auto size-fit ease-linear animate-in fade-in"
style={{
animationDuration: "var(--transition-length)",
animationDelay: "var(--delay)",
}}
>
{currentPercent}%
</span>
+25
View File
@@ -0,0 +1,25 @@
import { createContext } from "react";
export interface AuthState {
user: { username: string; role: string | null } | null;
allowedCameras: string[];
isLoading: boolean;
isAuthenticated: boolean; // true if auth is required
}
interface AuthContextType {
auth: AuthState;
login: (user: AuthState["user"]) => void;
logout: () => void;
}
export const AuthContext = createContext<AuthContextType>({
auth: {
user: null,
allowedCameras: [],
isLoading: true,
isAuthenticated: false,
},
login: () => {},
logout: () => {},
});
@@ -1,30 +1,7 @@
import axios from "axios";
import { createContext, useEffect, useState } from "react";
import { useEffect, useState } from "react";
import useSWR from "swr";
interface AuthState {
user: { username: string; role: string | null } | null;
allowedCameras: string[];
isLoading: boolean;
isAuthenticated: boolean; // true if auth is required
}
interface AuthContextType {
auth: AuthState;
login: (user: AuthState["user"]) => void;
logout: () => void;
}
export const AuthContext = createContext<AuthContextType>({
auth: {
user: null,
allowedCameras: [],
isLoading: true,
isAuthenticated: false,
},
login: () => {},
logout: () => {},
});
import { AuthContext, AuthState } from "./auth-context";
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [auth, setAuth] = useState<AuthState>({
+1 -1
View File
@@ -6,7 +6,7 @@ import { TooltipProvider } from "@/components/ui/tooltip";
import { StatusBarMessagesProvider } from "@/context/statusbar-provider";
import { LanguageProvider } from "./language-provider";
import { StreamingSettingsProvider } from "./streaming-settings-provider";
import { AuthProvider } from "./auth-context";
import { AuthProvider } from "./auth-provider";
type TProvidersProps = {
children: ReactNode;
+28
View File
@@ -0,0 +1,28 @@
import { createContext } from "react";
export type StatusMessage = {
id: string;
text: string;
color?: string;
link?: string;
};
export type StatusMessagesState = {
[key: string]: StatusMessage[];
};
type StatusBarMessagesContextValue = {
messages: StatusMessagesState;
addMessage: (
key: string,
message: string,
color?: string,
messageId?: string,
link?: string,
) => string | undefined;
removeMessage: (key: string, messageId: string) => void;
clearMessages: (key: string) => void;
};
export const StatusBarMessagesContext =
createContext<StatusBarMessagesContextValue | null>(null);
+4 -33
View File
@@ -1,42 +1,13 @@
import { useState, ReactNode, useCallback, useMemo } from "react";
import {
createContext,
useState,
ReactNode,
useCallback,
useMemo,
} from "react";
export type StatusMessage = {
id: string;
text: string;
color?: string;
link?: string;
};
export type StatusMessagesState = {
[key: string]: StatusMessage[];
};
StatusBarMessagesContext,
StatusMessagesState,
} from "@/context/statusbar-context";
type StatusBarMessagesProviderProps = {
children: ReactNode;
};
type StatusBarMessagesContextValue = {
messages: StatusMessagesState;
addMessage: (
key: string,
message: string,
color?: string,
messageId?: string,
link?: string,
) => string | undefined;
removeMessage: (key: string, messageId: string) => void;
clearMessages: (key: string) => void;
};
export const StatusBarMessagesContext =
createContext<StatusBarMessagesContextValue | null>(null);
export function StatusBarMessagesProvider({
children,
}: StatusBarMessagesProviderProps) {
+18 -18
View File
@@ -48,126 +48,126 @@ html {
font-style: normal;
font-weight: 100;
font-display: swap;
src: url("../fonts/Inter-Thin.woff2") format("woff2");
src: url("./assets/fonts/Inter-Thin.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 100;
font-display: swap;
src: url("../fonts/Inter-ThinItalic.woff2") format("woff2");
src: url("./assets/fonts/Inter-ThinItalic.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 200;
font-display: swap;
src: url("../fonts/Inter-ExtraLight.woff2") format("woff2");
src: url("./assets/fonts/Inter-ExtraLight.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 200;
font-display: swap;
src: url("../fonts/Inter-ExtraLightItalic.woff2") format("woff2");
src: url("./assets/fonts/Inter-ExtraLightItalic.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 300;
font-display: swap;
src: url("../fonts/Inter-Light.woff2") format("woff2");
src: url("./assets/fonts/Inter-Light.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 300;
font-display: swap;
src: url("../fonts/Inter-LightItalic.woff2") format("woff2");
src: url("./assets/fonts/Inter-LightItalic.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("../fonts/Inter-Regular.woff2") format("woff2");
src: url("./assets/fonts/Inter-Regular.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 400;
font-display: swap;
src: url("../fonts/Inter-Italic.woff2") format("woff2");
src: url("./assets/fonts/Inter-Italic.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("../fonts/Inter-Medium.woff2") format("woff2");
src: url("./assets/fonts/Inter-Medium.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 500;
font-display: swap;
src: url("../fonts/Inter-MediumItalic.woff2") format("woff2");
src: url("./assets/fonts/Inter-MediumItalic.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("../fonts/Inter-SemiBold.woff2") format("woff2");
src: url("./assets/fonts/Inter-SemiBold.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 600;
font-display: swap;
src: url("../fonts/Inter-SemiBoldItalic.woff2") format("woff2");
src: url("./assets/fonts/Inter-SemiBoldItalic.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("../fonts/Inter-Bold.woff2") format("woff2");
src: url("./assets/fonts/Inter-Bold.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 700;
font-display: swap;
src: url("../fonts/Inter-BoldItalic.woff2") format("woff2");
src: url("./assets/fonts/Inter-BoldItalic.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 800;
font-display: swap;
src: url("../fonts/Inter-ExtraBold.woff2") format("woff2");
src: url("./assets/fonts/Inter-ExtraBold.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 800;
font-display: swap;
src: url("../fonts/Inter-ExtraBoldItalic.woff2") format("woff2");
src: url("./assets/fonts/Inter-ExtraBoldItalic.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 900;
font-display: swap;
src: url("../fonts/Inter-Black.woff2") format("woff2");
src: url("./assets/fonts/Inter-Black.woff2") format("woff2");
}
@font-face {
font-family: "Inter";
font-style: italic;
font-weight: 900;
font-display: swap;
src: url("../fonts/Inter-BlackItalic.woff2") format("woff2");
src: url("./assets/fonts/Inter-BlackItalic.woff2") format("woff2");
}
.react-resizable-handle {
+2 -3
View File
@@ -61,9 +61,8 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import PreviewPlayer, {
PreviewController,
} from "@/components/player/PreviewPlayer";
import PreviewPlayer from "@/components/player/PreviewPlayer";
import { PreviewController } from "@/components/player/PreviewController";
import SummaryTimeline from "@/components/timeline/SummaryTimeline";
import { RecordingStartingPoint } from "@/types/record";
import VideoControls from "@/components/player/VideoControls";
+2 -3
View File
@@ -3,9 +3,8 @@ import ReviewFilterGroup from "@/components/filter/ReviewFilterGroup";
import DebugReplayDialog from "@/components/overlay/DebugReplayDialog";
import ExportDialog from "@/components/overlay/ExportDialog";
import ActionsDropdown from "@/components/overlay/ActionsDropdown";
import PreviewPlayer, {
PreviewController,
} from "@/components/player/PreviewPlayer";
import PreviewPlayer from "@/components/player/PreviewPlayer";
import { PreviewController } from "@/components/player/PreviewController";
import { DynamicVideoController } from "@/components/player/dynamic/DynamicVideoController";
import DynamicVideoPlayer from "@/components/player/dynamic/DynamicVideoPlayer";
import QualitySelector from "@/components/player/QualitySelector";
@@ -58,7 +58,7 @@ import {
import type { ProfileState } from "@/types/profile";
import { getProfileColor } from "@/utils/profileColors";
import { isReplayCamera } from "@/utils/cameraUtil";
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
import { StatusBarMessagesContext } from "@/context/statusbar-context";
import { cn } from "@/lib/utils";
import {
Select,
@@ -12,7 +12,7 @@ import { toast } from "sonner";
import { Separator } from "@/components/ui/separator";
import { Link } from "react-router-dom";
import { LuExternalLink } from "react-icons/lu";
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
import { StatusBarMessagesContext } from "@/context/statusbar-context";
import {
Select,
SelectContent,
@@ -14,7 +14,7 @@ import { useCallback, useContext, useState } from "react";
import { useTranslation } from "react-i18next";
import axios from "axios";
import { toast } from "sonner";
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
import { StatusBarMessagesContext } from "@/context/statusbar-context";
import { cn } from "@/lib/utils";
type RegionGridSettingsViewProps = {