diff --git a/src/cssStyles.tsx b/src/cssStyles.tsx index a96b39391..18472feff 100644 --- a/src/cssStyles.tsx +++ b/src/cssStyles.tsx @@ -6,6 +6,9 @@ import React from "react"; import emotionNormalize from "emotion-normalize"; import { createTheme } from "@mui/material/styles"; import { Theme, useTheme } from "./themes"; +import { + DEFAULT_CONFIG as APPKIT_CONFIG, +} from "@opencast/appkit"; import { StylesConfig } from "react-select"; /** @@ -35,8 +38,8 @@ export const globalStyle = (theme: Theme) => css({ // When to switch behaviour based on screen width -export const BREAKPOINT_SMALL = 450; -export const BREAKPOINT_MEDIUM = 650; +/** Breakpoint values */ +export const BREAKPOINTS = APPKIT_CONFIG.breakpoints; /** * CSS for buttons @@ -433,3 +436,9 @@ export const backgroundBoxStyle = (theme: Theme) => css(({ padding: "20px", gap: "25px", })); + +export const undisplay = (maxWidth: number) => css({ + [`@media (max-width: ${maxWidth}px)`]: { + display: "none", + }, +}); diff --git a/src/img/opencast-editor-narrow.svg b/src/img/opencast-editor-narrow.svg new file mode 100644 index 000000000..c4a3c598e --- /dev/null +++ b/src/img/opencast-editor-narrow.svg @@ -0,0 +1,55 @@ + + + diff --git a/src/main/CuttingActions.tsx b/src/main/CuttingActions.tsx index b2612d70b..f65977aa5 100644 --- a/src/main/CuttingActions.tsx +++ b/src/main/CuttingActions.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { basicButtonStyle, customIconStyle } from "../cssStyles"; +import { BREAKPOINTS, basicButtonStyle, customIconStyle, undisplay } from "../cssStyles"; import { IconType } from "react-icons"; import { LuScissors, LuChevronLeft, LuChevronRight, LuTrash, LuMoveHorizontal } from "react-icons/lu"; @@ -110,6 +110,8 @@ const CuttingActions: React.FC = () => { flexDirection: "row" as const, justifyContent: "center", alignItems: "center", + + flexWrap: "wrap", }); const verticalLineStyle = css({ @@ -246,7 +248,7 @@ const CuttingActionsButton: React.FC = ({ }} > - {actionName} + {actionName} ); @@ -291,8 +293,10 @@ const MarkAsDeletedButton: React.FC = ({ } }} > - {isCurrentSegmentAlive ? : } -
{isCurrentSegmentAlive ? t("cuttingActions.delete-button") : t("cuttingActions.restore-button")}
+ {isCurrentSegmentAlive ? : } + + {isCurrentSegmentAlive ? t("cuttingActions.delete-button") : t("cuttingActions.restore-button")} + ); diff --git a/src/main/Header.tsx b/src/main/Header.tsx index f717fc034..0035c07be 100644 --- a/src/main/Header.tsx +++ b/src/main/Header.tsx @@ -10,10 +10,17 @@ import { LuMoon, LuSun } from "react-icons/lu"; import { HiOutlineTranslate } from "react-icons/hi"; import { LuKeyboard } from "react-icons/lu"; import { MainMenuStateNames } from "../types"; -import { basicButtonStyle, BREAKPOINT_MEDIUM, BREAKPOINT_SMALL } from "../cssStyles"; +import { basicButtonStyle, BREAKPOINTS, undisplay } from "../cssStyles"; import { selectIsEnd } from "../redux/endSlice"; -import { checkboxMenuItem, HeaderMenuItemDef, ProtoButton, useColorScheme, WithHeaderMenu } from "@opencast/appkit"; +import { + checkboxMenuItem, + HeaderMenuItemDef, + ProtoButton, + screenWidthAtMost, + useColorScheme, + WithHeaderMenu, +} from "@opencast/appkit"; import { IconType } from "react-icons"; import i18next from "i18next"; import { languages as lngs } from "../i18n/lngs-generated"; @@ -68,6 +75,10 @@ function Header() { backgroundColor: theme.header_button_hover_bg, color: `${theme.header_text}`, }, + + [screenWidthAtMost(BREAKPOINTS.medium)]: { + fontSize: 0, + }, }); return ( @@ -184,7 +195,7 @@ const LanguageButton: React.FC = () => { menu={{ label, items: menuItems, - breakpoint: BREAKPOINT_SMALL, + breakpoint: BREAKPOINTS.small, }} > @@ -210,7 +221,7 @@ const ThemeButton: React.FC = () => { menu={{ label: t("theme.appearance"), items: menuItems, - breakpoint: BREAKPOINT_MEDIUM, + breakpoint: BREAKPOINTS.medium, }}> ( css={[basicButtonStyle(theme), themeSelectorButtonStyle]} > - {label} + {label} ); }); diff --git a/src/main/MainMenu.tsx b/src/main/MainMenu.tsx index f2c5cc99f..1082ad160 100644 --- a/src/main/MainMenu.tsx +++ b/src/main/MainMenu.tsx @@ -13,7 +13,7 @@ import { setPageNumber } from "../redux/finishSlice"; import { MainMenuStateNames } from "../types"; import { settings } from "../config"; -import { basicButtonStyle } from "../cssStyles"; +import { basicButtonStyle, BREAKPOINTS } from "../cssStyles"; import { setIsPlaying } from "../redux/videoSlice"; import { useTranslation } from "react-i18next"; @@ -21,6 +21,7 @@ import { resetPostRequestState } from "../redux/workflowPostSlice"; import { setIsDisplayEditView } from "../redux/subtitleSlice"; import { useTheme } from "../themes"; +import { screenWidthAtMost } from "@opencast/appkit"; /** * A container for selecting the functionality shown in the main part of the app @@ -42,6 +43,10 @@ const MainMenu: React.FC = () => { overflowY: "auto", background: `${theme.menu_background}`, gap: "30px", + [screenWidthAtMost(BREAKPOINTS.large)]: { + minWidth: "60px", + padding: "20px 10px", + }, }); return ( @@ -142,6 +147,10 @@ export const MainMenuButton: React.FC = ({ boxShadow: `${theme.boxShadow}`, }, flexDirection: "column", + [screenWidthAtMost(BREAKPOINTS.large)]: { + height: "60px", + minHeight: "40px", + }, }); return ( @@ -159,8 +168,15 @@ export const MainMenuButton: React.FC = ({ fontSize: 36, width: "36px", height: "auto", - }} /> - {bottomText &&
{bottomText}
} + }}/> + {bottomText && +
+ {bottomText} +
} ); }; diff --git a/src/main/Metadata.tsx b/src/main/Metadata.tsx index e1ced778d..d9811ab6a 100644 --- a/src/main/Metadata.tsx +++ b/src/main/Metadata.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from "react"; import { css } from "@emotion/react"; -import { calendarStyle, errorBoxStyle, selectFieldStyle, titleStyle, titleStyleBold } from "../cssStyles"; +import { BREAKPOINTS, calendarStyle, errorBoxStyle, selectFieldStyle, titleStyle, titleStyleBold } from "../cssStyles"; import { useAppDispatch, useAppSelector } from "../redux/store"; import { @@ -27,6 +27,7 @@ import { useTheme } from "../themes"; import { ThemeProvider } from "@mui/material/styles"; import { cloneDeep } from "lodash"; import { ParseKeys } from "i18next"; +import { screenWidthAtMost } from "@opencast/appkit"; /** * Creates a Metadata form @@ -96,6 +97,12 @@ const Metadata: React.FC = () => { marginRight: "auto", minWidth: "50%", display: "grid", + [screenWidthAtMost(1550)]: { + minWidth: "70%", + }, + [screenWidthAtMost(BREAKPOINTS.medium)]: { + minWidth: "90%", + }, }); const catalogStyle = css({ diff --git a/src/main/VideoControls.tsx b/src/main/VideoControls.tsx index c5c2c70ec..a66d75f2f 100644 --- a/src/main/VideoControls.tsx +++ b/src/main/VideoControls.tsx @@ -11,7 +11,7 @@ import { } from "../redux/videoSlice"; import { convertMsToReadableString } from "../util/utilityFunctions"; -import { basicButtonStyle } from "../cssStyles"; +import { BREAKPOINTS, basicButtonStyle, undisplay } from "../cssStyles"; import { KEYMAP, rewriteKeys } from "../globalKeys"; import { useTranslation } from "react-i18next"; @@ -175,8 +175,9 @@ const PreviewMode: React.FC<{ if (event.key === " ") { switchPlayPreview(undefined); } - }}> -
+ }} + > +
{t("video.previewButton")}
{isPlayPreview ? @@ -360,9 +361,9 @@ const TimeDisplay: React.FC<{ {new Date((currentlyAt ? currentlyAt : 0)).toISOString().substr(11, 10)} - {" / "} +
{" / "}
-
{new Date((duration ? duration : 0)).toISOString().substr(11, 10)}
diff --git a/src/util/utilityFunctions.ts b/src/util/utilityFunctions.ts index 7bb075953..ed0d86288 100644 --- a/src/util/utilityFunctions.ts +++ b/src/util/utilityFunctions.ts @@ -1,7 +1,7 @@ import { nanoid } from "@reduxjs/toolkit"; import { WebVTTParser, WebVTTSerializer } from "webvtt-parser"; import { ExtendedSubtitleCue, SubtitleCue } from "../types"; -import { useEffect, useRef } from "react"; +import { useEffect, useState, useRef } from "react"; export const roundToDecimalPlace = (num: number, decimalPlace: number) => { const decimalFactor = Math.pow(10, decimalPlace); @@ -149,6 +149,36 @@ export function languageCodeToName(lang: string | undefined): string | undefined } } +/** + * @returns the current window width and height + */ +function getWindowDimensions() { + const { innerWidth: width, innerHeight: height } = window; + return { + width, + height, + }; +} + +/** + * A hook for window dimensions + */ +export default function useWindowDimensions() { + const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions()); + + useEffect(() => { + function handleResize() { + setWindowDimensions(getWindowDimensions()); + } + + window.addEventListener("resize", handleResize); + return () => window.removeEventListener("resize", handleResize); + }, []); + + return windowDimensions; + +} + // Runs a callback every delay milliseconds // Pass delay = null to stop // Based off: https://overreacted.io/making-setinterval-declarative-with-react-hooks/