diff --git a/client/src/backend/components/resource/form/kind/Video/Video.styles.js b/client/src/backend/components/resource/form/kind/Video/Video.styles.js
new file mode 100644
index 0000000000..d355377821
--- /dev/null
+++ b/client/src/backend/components/resource/form/kind/Video/Video.styles.js
@@ -0,0 +1,21 @@
+import styled from "@emotion/styled";
+
+export const Group = styled.div`
+ display: flex;
+ flex-wrap: wrap;
+ gap: 40px;
+
+ > * {
+ inline-size: max(200px, min(calc(50% - 20px), 400px));
+ display: flex;
+ flex-direction: column;
+
+ > div {
+ flex-grow: 1;
+ }
+
+ > label {
+ block-size: 15px;
+ }
+ }
+`;
diff --git a/client/src/backend/components/resource/form/kind/Video.js b/client/src/backend/components/resource/form/kind/Video/index.js
similarity index 72%
rename from client/src/backend/components/resource/form/kind/Video.js
rename to client/src/backend/components/resource/form/kind/Video/index.js
index 0a92b4a6a4..ef9d05478c 100644
--- a/client/src/backend/components/resource/form/kind/Video.js
+++ b/client/src/backend/components/resource/form/kind/Video/index.js
@@ -2,6 +2,7 @@ import React, { PureComponent } from "react";
import PropTypes from "prop-types";
import Form from "global/components/form";
import { withTranslation } from "react-i18next";
+import * as Styled from "./Video.styles";
class ResourceFormKindVideo extends PureComponent {
static displayName = "Resource.Form.Kind.Video";
@@ -42,15 +43,26 @@ class ResourceFormKindVideo extends PureComponent {
renderVideoAttachmentForm() {
return (
-
+
+
+
+
);
}
diff --git a/client/src/backend/containers/resource/breadcrumbs.js b/client/src/backend/containers/resource/breadcrumbs.js
index 0ddb64bc80..249391a720 100644
--- a/client/src/backend/containers/resource/breadcrumbs.js
+++ b/client/src/backend/containers/resource/breadcrumbs.js
@@ -24,7 +24,7 @@ export const getBreadcrumbs = (resource, project, belongsToJournalIssue, t) => {
}
];
- return belongsToJournalIssue
+ return belongsToJournalIssue && project.relationships.journal
? [
{
to: lh.link("backendJournals"),
diff --git a/client/src/config/app/locale/en-US/json/backend/resources.json b/client/src/config/app/locale/en-US/json/backend/resources.json
index 20b0a13c38..ba0688a62a 100644
--- a/client/src/config/app/locale/en-US/json/backend/resources.json
+++ b/client/src/config/app/locale/en-US/json/backend/resources.json
@@ -59,7 +59,8 @@
"presentation": "Presentation",
"interactive": "Interactive",
"resource_kind": "Resource Kind",
- "kind": "Kind"
+ "kind": "Kind",
+ "captions": "Captions"
},
"properties": {
"title_instructions": "This field accepts Markdown.",
diff --git a/client/src/frontend/components/resource-player/Video/index.js b/client/src/frontend/components/resource-player/Video/index.js
index 62651c3b5e..86c7474e81 100644
--- a/client/src/frontend/components/resource-player/Video/index.js
+++ b/client/src/frontend/components/resource-player/Video/index.js
@@ -104,23 +104,49 @@ class ResourcePlayerVideo extends Component {
this.props.dispatch(notificationActions.addNotification(notification));
};
+ trackRef = el => {
+ if (!el) return;
+
+ el.addEventListener("load", () => {
+ if (!el.track?.cues) return;
+ Array.from(el.track.cues).forEach(c => {
+ // eslint-disable-next-line no-param-reassign
+ c.line = -3;
+ });
+ });
+ };
+
renderFileVideo() {
if (!this.state.inBrowser) return null;
const {
variantPosterStyles,
- attachmentStyles
+ attachmentStyles,
+ captionsTrackUrl
} = this.props.resource.attributes;
+ // Use the proxy if running over ports in dev to avoid CORS error
+ const captionsSrc =
+ process.env.NODE_ENV === "development"
+ ? captionsTrackUrl.replace("3020", "3010")
+ : captionsTrackUrl;
+
return (
);
diff --git a/client/src/frontend/components/resource-player/Video/styles.js b/client/src/frontend/components/resource-player/Video/styles.js
index b5c5159cc7..6bd816d38a 100644
--- a/client/src/frontend/components/resource-player/Video/styles.js
+++ b/client/src/frontend/components/resource-player/Video/styles.js
@@ -6,6 +6,13 @@ export const VideoWrapper = styled.div`
left: 0;
width: 100%;
height: 100%;
+
+ video::cue {
+ font-size: 16px;
+ background: rgba(0, 0, 0, 0.75);
+ color: var(--color-base-neutral-white);
+ font-family: var(--font-family-heading);
+ }
`;
export const Video = styled.iframe`
diff --git a/client/src/global/components/form/Upload/index.js b/client/src/global/components/form/Upload/index.js
index 4692920c29..fa89c074e6 100644
--- a/client/src/global/components/form/Upload/index.js
+++ b/client/src/global/components/form/Upload/index.js
@@ -57,6 +57,10 @@ export class FormUpload extends Component {
accepts: "application/json",
extensions: "json"
},
+ vtt: {
+ accepts: "text/vtt",
+ extensions: "vtt"
+ },
any: {
accepts: null,
extensions: null
diff --git a/client/src/theme/styles/vendor/react-html5video.js b/client/src/theme/styles/vendor/react-html5video.js
index 3ed675f395..51eb51cf86 100644
--- a/client/src/theme/styles/vendor/react-html5video.js
+++ b/client/src/theme/styles/vendor/react-html5video.js
@@ -158,6 +158,16 @@ export default `
.rh5v-Captions_component {
position: relative;
+
+ &:has(.rh5v-Captions_activeTrackItem) {
+ svg {
+ fill: var(--hover-color);
+
+ &:hover {
+ fill: var(--color-interaction-dark);
+ }
+ }
+ }
}
.rh5v-Captions_component:hover {
@@ -178,7 +188,8 @@ export default `
}
.rh5v-Captions_icon {
- padding: 5px;
+ padding: 1px;
+ margin-block-start: 4px;
}
.rh5v-Captions_trackList {