mirror of
https://github.com/movie-web/movie-web.git
synced 2025-01-21 07:51:39 +00:00
suggested changes
This commit is contained in:
parent
c472e7f7b8
commit
b9b0380dfe
29
src/components/CaptionColorSelector.tsx
Normal file
29
src/components/CaptionColorSelector.tsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { useSettings } from "@/state/settings";
|
||||||
|
import { Icon, Icons } from "./Icon";
|
||||||
|
|
||||||
|
export const colors = ["#ffffff", "#00ffff", "#ffff00"];
|
||||||
|
export default function CaptionColorSelector({ color }: { color: string }) {
|
||||||
|
const { captionSettings, setCaptionColor } = useSettings();
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`flex h-8 w-8 items-center justify-center rounded transition-[background-color,transform] duration-100 hover:bg-[#1c161b79] active:scale-110 ${
|
||||||
|
color === captionSettings.style.color ? "bg-[#1C161B]" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => setCaptionColor(color)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="h-4 w-4 cursor-pointer appearance-none rounded-full"
|
||||||
|
style={{
|
||||||
|
backgroundColor: color,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Icon
|
||||||
|
className={[
|
||||||
|
"absolute text-xs text-[#1C161B]",
|
||||||
|
color === captionSettings.style.color ? "" : "hidden",
|
||||||
|
].join(" ")}
|
||||||
|
icon={Icons.CHECKMARK}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -40,7 +40,7 @@ export function ModalCard(props: { className?: string; children?: ReactNode }) {
|
||||||
<div
|
<div
|
||||||
className={[
|
className={[
|
||||||
"relative mx-2 w-[500px] overflow-hidden rounded-lg bg-denim-200 px-10 py-10 sm:w-[500px] md:w-[500px] lg:w-[1000px]",
|
"relative mx-2 w-[500px] overflow-hidden rounded-lg bg-denim-200 px-10 py-10 sm:w-[500px] md:w-[500px] lg:w-[1000px]",
|
||||||
props.className,
|
props.className ?? "",
|
||||||
].join(" ")}
|
].join(" ")}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|
|
@ -184,7 +184,7 @@ export type LangCode =
|
||||||
| "za"
|
| "za"
|
||||||
| "zh"
|
| "zh"
|
||||||
| "zu";
|
| "zu";
|
||||||
type CaptionLanguageOptions = {
|
export type CaptionLanguageOption = {
|
||||||
id: LangCode;
|
id: LangCode;
|
||||||
name: string;
|
name: string;
|
||||||
englishName: string;
|
englishName: string;
|
||||||
|
@ -212,7 +212,7 @@ type CaptionLanguageOptions = {
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
// SOFTWARE.
|
// SOFTWARE.
|
||||||
export const captionLanguages: CaptionLanguageOptions[] = [
|
export const captionLanguages: CaptionLanguageOption[] = [
|
||||||
{
|
{
|
||||||
id: "none",
|
id: "none",
|
||||||
englishName: "None",
|
englishName: "None",
|
||||||
|
|
|
@ -22,14 +22,10 @@ export function CaptionCue({ text, scale }: { text?: string; scale?: number }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p
|
<p
|
||||||
className={[
|
className="pointer-events-none mb-1 select-none rounded px-4 py-1 text-center [text-shadow:0_2px_4px_rgba(0,0,0,0.5)]"
|
||||||
"pointer-events-none mb-1 select-none rounded px-4 py-1 text-center [text-shadow:0_2px_4px_rgba(0,0,0,0.5)]",
|
|
||||||
].join(" ")}
|
|
||||||
style={{
|
style={{
|
||||||
...captionSettings.style,
|
...captionSettings.style,
|
||||||
fontSize: !scale
|
fontSize: captionSettings.style.fontSize * (scale ?? 1),
|
||||||
? captionSettings.style.fontSize
|
|
||||||
: captionSettings.style.fontSize * scale,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
|
|
@ -4,8 +4,10 @@ import { useFloatingRouter } from "@/hooks/useFloatingRouter";
|
||||||
import { useSettings } from "@/state/settings";
|
import { useSettings } from "@/state/settings";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { Icon, Icons } from "@/components/Icon";
|
|
||||||
import { Slider } from "@/components/Slider";
|
import { Slider } from "@/components/Slider";
|
||||||
|
import CaptionColorSelector, {
|
||||||
|
colors,
|
||||||
|
} from "@/components/CaptionColorSelector";
|
||||||
|
|
||||||
export function CaptionSettingsPopout(props: {
|
export function CaptionSettingsPopout(props: {
|
||||||
router: ReturnType<typeof useFloatingRouter>;
|
router: ReturnType<typeof useFloatingRouter>;
|
||||||
|
@ -16,11 +18,9 @@ export function CaptionSettingsPopout(props: {
|
||||||
const {
|
const {
|
||||||
captionSettings,
|
captionSettings,
|
||||||
setCaptionBackgroundColor,
|
setCaptionBackgroundColor,
|
||||||
setCaptionColor,
|
|
||||||
setCaptionDelay,
|
setCaptionDelay,
|
||||||
setCaptionFontSize,
|
setCaptionFontSize,
|
||||||
} = useSettings();
|
} = useSettings();
|
||||||
const colors = ["#ffffff", "#00ffff", "#ffff00"];
|
|
||||||
return (
|
return (
|
||||||
<FloatingView {...props.router.pageProps(props.prefix)} width={375}>
|
<FloatingView {...props.router.pageProps(props.prefix)} width={375}>
|
||||||
<FloatingCardView.Header
|
<FloatingCardView.Header
|
||||||
|
@ -39,7 +39,7 @@ export function CaptionSettingsPopout(props: {
|
||||||
onChange={(e) => setCaptionDelay(e.target.valueAsNumber)}
|
onChange={(e) => setCaptionDelay(e.target.valueAsNumber)}
|
||||||
/>
|
/>
|
||||||
<Slider
|
<Slider
|
||||||
label="Size"
|
label={t("videoPlayer.popouts.captionPreferences.fontSize") as string}
|
||||||
min={14}
|
min={14}
|
||||||
step={1}
|
step={1}
|
||||||
max={60}
|
max={60}
|
||||||
|
@ -71,26 +71,7 @@ export function CaptionSettingsPopout(props: {
|
||||||
</label>
|
</label>
|
||||||
<div className="flex flex-row gap-2">
|
<div className="flex flex-row gap-2">
|
||||||
{colors.map((color) => (
|
{colors.map((color) => (
|
||||||
<div
|
<CaptionColorSelector color={color} />
|
||||||
className={`flex h-8 w-8 items-center justify-center rounded transition-[background-color,transform] duration-100 hover:bg-[#1c161b79] active:scale-110 ${
|
|
||||||
color === captionSettings.style.color ? "bg-[#1C161B]" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => setCaptionColor(color)}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="h-4 w-4 cursor-pointer appearance-none rounded-full"
|
|
||||||
style={{
|
|
||||||
backgroundColor: color,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Icon
|
|
||||||
className={[
|
|
||||||
"absolute text-xs text-[#1C161B]",
|
|
||||||
color === captionSettings.style.color ? "" : "hidden",
|
|
||||||
].join(" ")}
|
|
||||||
icon={Icons.CHECKMARK}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,10 +4,18 @@ import { Modal, ModalCard } from "@/components/layout/Modal";
|
||||||
import { useSettings } from "@/state/settings";
|
import { useSettings } from "@/state/settings";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { CaptionCue } from "@/video/components/actions/CaptionRendererAction";
|
import { CaptionCue } from "@/video/components/actions/CaptionRendererAction";
|
||||||
import { Slider } from "@/video/components/popouts/CaptionSettingsPopout";
|
import {
|
||||||
import { LangCode, captionLanguages } from "@/setup/iso6391";
|
CaptionLanguageOption,
|
||||||
|
LangCode,
|
||||||
|
captionLanguages,
|
||||||
|
} from "@/setup/iso6391";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { appLanguageOptions } from "@/setup/i18n";
|
import { appLanguageOptions } from "@/setup/i18n";
|
||||||
|
import CaptionColorSelector, {
|
||||||
|
colors,
|
||||||
|
} from "@/components/CaptionColorSelector";
|
||||||
|
import { Slider } from "@/components/Slider";
|
||||||
|
import { conf } from "@/setup/config";
|
||||||
|
|
||||||
export default function SettingsModal(props: {
|
export default function SettingsModal(props: {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
@ -19,16 +27,18 @@ export default function SettingsModal(props: {
|
||||||
setLanguage,
|
setLanguage,
|
||||||
setCaptionLanguage,
|
setCaptionLanguage,
|
||||||
setCaptionBackgroundColor,
|
setCaptionBackgroundColor,
|
||||||
setCaptionColor,
|
|
||||||
setCaptionFontSize,
|
setCaptionFontSize,
|
||||||
} = useSettings();
|
} = useSettings();
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
|
|
||||||
const colors = ["#ffffff", "#00ffff", "#ffff00"];
|
|
||||||
const selectedCaptionLanguage = useMemo(
|
const selectedCaptionLanguage = useMemo(
|
||||||
() => captionLanguages.find((l) => l.id === captionSettings.language)!,
|
() => captionLanguages.find((l) => l.id === captionSettings.language),
|
||||||
[captionSettings.language]
|
[captionSettings.language]
|
||||||
);
|
) as CaptionLanguageOption;
|
||||||
|
const appLanguage = useMemo(
|
||||||
|
() => appLanguageOptions.find((l) => l.id === language),
|
||||||
|
[language]
|
||||||
|
) as CaptionLanguageOption;
|
||||||
const captionBackgroundOpacity = (
|
const captionBackgroundOpacity = (
|
||||||
(parseInt(captionSettings.style.backgroundColor.substring(7, 9), 16) /
|
(parseInt(captionSettings.style.backgroundColor.substring(7, 9), 16) /
|
||||||
255) *
|
255) *
|
||||||
|
@ -54,9 +64,7 @@ export default function SettingsModal(props: {
|
||||||
{t("settings.language")}
|
{t("settings.language")}
|
||||||
</label>
|
</label>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
selectedItem={
|
selectedItem={appLanguage}
|
||||||
appLanguageOptions.find((l) => l.id === language)!
|
|
||||||
}
|
|
||||||
setSelectedItem={(val) => {
|
setSelectedItem={(val) => {
|
||||||
i18n.changeLanguage(val.id);
|
i18n.changeLanguage(val.id);
|
||||||
setLanguage(val.id as LangCode);
|
setLanguage(val.id as LangCode);
|
||||||
|
@ -78,7 +86,11 @@ export default function SettingsModal(props: {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col justify-between">
|
<div className="flex flex-col justify-between">
|
||||||
<Slider
|
<Slider
|
||||||
label="Size"
|
label={
|
||||||
|
t(
|
||||||
|
"videoPlayer.popouts.captionPreferences.fontSize"
|
||||||
|
) as string
|
||||||
|
}
|
||||||
min={14}
|
min={14}
|
||||||
step={1}
|
step={1}
|
||||||
max={60}
|
max={60}
|
||||||
|
@ -86,7 +98,11 @@ export default function SettingsModal(props: {
|
||||||
onChange={(e) => setCaptionFontSize(e.target.valueAsNumber)}
|
onChange={(e) => setCaptionFontSize(e.target.valueAsNumber)}
|
||||||
/>
|
/>
|
||||||
<Slider
|
<Slider
|
||||||
label={t("videoPlayer.popouts.captionPreferences.opacity")}
|
label={
|
||||||
|
t(
|
||||||
|
"videoPlayer.popouts.captionPreferences.opacity"
|
||||||
|
) as string
|
||||||
|
}
|
||||||
step={1}
|
step={1}
|
||||||
min={0}
|
min={0}
|
||||||
max={255}
|
max={255}
|
||||||
|
@ -105,30 +121,7 @@ export default function SettingsModal(props: {
|
||||||
</label>
|
</label>
|
||||||
<div className="flex flex-row gap-2">
|
<div className="flex flex-row gap-2">
|
||||||
{colors.map((color) => (
|
{colors.map((color) => (
|
||||||
<div
|
<CaptionColorSelector color={color} />
|
||||||
className={`flex h-8 w-8 items-center justify-center rounded transition-[background-color,transform] duration-100 hover:bg-[#1c161b79] active:scale-110 ${
|
|
||||||
color === captionSettings.style.color
|
|
||||||
? "bg-[#1C161B]"
|
|
||||||
: ""
|
|
||||||
}`}
|
|
||||||
onClick={() => setCaptionColor(color)}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="h-4 w-4 cursor-pointer appearance-none rounded-full"
|
|
||||||
style={{
|
|
||||||
backgroundColor: color,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Icon
|
|
||||||
className={[
|
|
||||||
"absolute text-xs text-[#1C161B]",
|
|
||||||
color === captionSettings.style.color
|
|
||||||
? ""
|
|
||||||
: "hidden",
|
|
||||||
].join(" ")}
|
|
||||||
icon={Icons.CHECKMARK}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -149,6 +142,7 @@ export default function SettingsModal(props: {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="float-right mt-1 text-sm">v{conf().APP_VERSION}</div>
|
||||||
</ModalCard>
|
</ModalCard>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue