mirror of
https://github.com/bellingcat/ukraine-timemap.git
synced 2026-06-11 21:08:36 +03:00
Remove design-system dependency
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "7.12.3",
|
||||
"@forensic-architecture/design-system": "0.6.2",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "0.4.2",
|
||||
"@svgr/webpack": "5.4.0",
|
||||
"@testing-library/jest-dom": "^5.11.6",
|
||||
|
||||
@@ -484,13 +484,8 @@ export function makeNiceDate(datetime) {
|
||||
month: "long",
|
||||
day: "2-digit",
|
||||
});
|
||||
const [
|
||||
{ value: month },
|
||||
,
|
||||
{ value: day },
|
||||
,
|
||||
{ value: year },
|
||||
] = dateTimeFormat.formatToParts(datetime);
|
||||
const [{ value: month }, , { value: day }, , { value: year }] =
|
||||
dateTimeFormat.formatToParts(datetime);
|
||||
|
||||
return `${day} ${month}, ${year}`;
|
||||
}
|
||||
@@ -573,3 +568,5 @@ export function getFilterIdx(
|
||||
else if (narrativesExist && categoriesExist) return numCategoryPanels + 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
export const isEmptyString = (s) => s.length === 0;
|
||||
|
||||
232
src/components/controls/Card.js
Normal file
232
src/components/controls/Card.js
Normal file
@@ -0,0 +1,232 @@
|
||||
import React, { useState } from "react";
|
||||
import CardText from "./atoms/Text";
|
||||
import CardTime from "./atoms/Time";
|
||||
import CardButton from "./atoms/Button";
|
||||
import CardCaret from "./atoms/Caret";
|
||||
import CardCustom from "./atoms/CustomField";
|
||||
import CardMedia from "./atoms/Media";
|
||||
|
||||
import { makeNiceDate, isEmptyString } from "../../common/utilities";
|
||||
import hash from "object-hash";
|
||||
|
||||
export const generateCardLayout = {
|
||||
basic: ({ event }) => {
|
||||
return [
|
||||
[
|
||||
{
|
||||
kind: "date",
|
||||
title: "Incident Date",
|
||||
value: event.datetime || event.date || ``,
|
||||
},
|
||||
{
|
||||
kind: "text",
|
||||
title: "Location",
|
||||
value: event.location || `—`,
|
||||
},
|
||||
],
|
||||
[{ kind: "line-break", times: 0.4 }],
|
||||
[
|
||||
{
|
||||
kind: "text",
|
||||
title: "Summary",
|
||||
value: event.description || ``,
|
||||
scaleFont: 1.1,
|
||||
},
|
||||
],
|
||||
];
|
||||
},
|
||||
sourced: ({ event }) => {
|
||||
return [
|
||||
[
|
||||
{
|
||||
kind: "date",
|
||||
title: "Incident Date",
|
||||
value: event.datetime || event.date || ``,
|
||||
},
|
||||
{
|
||||
kind: "text",
|
||||
title: "Location",
|
||||
value: event.location || `—`,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
kind: "text",
|
||||
title: "Summary",
|
||||
value: event.description || ``,
|
||||
scaleFont: 1.1,
|
||||
},
|
||||
],
|
||||
...event.sources.flatMap((source, idx) => [
|
||||
[
|
||||
{
|
||||
kind: "text",
|
||||
title: `Source ${idx}`,
|
||||
value: source.description || ``,
|
||||
scaleFont: 1.1,
|
||||
},
|
||||
],
|
||||
source.paths.map((p) => ({
|
||||
kind: "media",
|
||||
title: "Media",
|
||||
value: [{ src: p, title: null }],
|
||||
})),
|
||||
]),
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
export const Card = ({
|
||||
content = [],
|
||||
isLoading = true,
|
||||
onSelect = () => {},
|
||||
sources = [],
|
||||
isSelected = false,
|
||||
language = "en-US",
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const toggle = () => setIsOpen(!isOpen);
|
||||
|
||||
// NB: should be internationalized.
|
||||
const renderTime = (field) => (
|
||||
<CardTime
|
||||
language={language}
|
||||
timelabel={makeNiceDate(field.value)}
|
||||
{...field}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderCaret = () =>
|
||||
sources.length === 0 && (
|
||||
<CardCaret toggle={() => toggle()} isOpen={isOpen} />
|
||||
);
|
||||
|
||||
const renderMedia = ({ media, idx }) => {
|
||||
return <CardMedia key={idx} src={media.src} title={media.title} />;
|
||||
};
|
||||
|
||||
function renderField(field) {
|
||||
switch (field.kind) {
|
||||
case "media":
|
||||
return (
|
||||
<div className="card-cell">
|
||||
{field.value.map((media, idx) => {
|
||||
return renderMedia({ media, idx });
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
case "line":
|
||||
return (
|
||||
<div style={{ height: `1rem`, width: `100%` }}>
|
||||
<hr />
|
||||
</div>
|
||||
);
|
||||
case "line-break":
|
||||
return (
|
||||
<div style={{ height: `${field.times || 1}rem`, width: `100%` }} />
|
||||
);
|
||||
case "item":
|
||||
// this is like a span
|
||||
return null;
|
||||
case "markdown":
|
||||
return <CardCustom {...field} />;
|
||||
case "tag":
|
||||
return (
|
||||
<div
|
||||
className="card-cell m0"
|
||||
style={{
|
||||
textTransform: `uppercase`,
|
||||
fontSize: `.8em`,
|
||||
lineHeight: `.8em`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: `flex-${field.align || `start`}`,
|
||||
}}
|
||||
>
|
||||
{field.value}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
case "button":
|
||||
return (
|
||||
<div className="card-cell">
|
||||
{field.title && <h4>{field.title}</h4>}
|
||||
{/* <div className="card-row"> */}
|
||||
{field.value.map((t, idx) => (
|
||||
<CardButton key={`card-button-${idx}`} {...t} />
|
||||
))}
|
||||
{/* </div> */}
|
||||
</div>
|
||||
);
|
||||
case "text":
|
||||
return !isEmptyString(field.value) && <CardText {...field} />;
|
||||
case "date":
|
||||
return renderTime(field);
|
||||
case "links":
|
||||
return (
|
||||
<div className="card-cell">
|
||||
{field.title && <h4>{field.title}</h4>}
|
||||
<div className="card-row m0">
|
||||
{field.value.map(({ text, href }, idx) => (
|
||||
<a href={href} key={`card-links-url-${idx}`}>
|
||||
{text}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
case "list":
|
||||
// Only render if some of the list's strings are non-empty
|
||||
const shouldFieldRender =
|
||||
!!field.value.length &&
|
||||
!!field.value.filter((s) => !isEmptyString(s)).length;
|
||||
return shouldFieldRender ? (
|
||||
// <div className="card-cell">
|
||||
<div>
|
||||
{field.title && <h4>{field.title}</h4>}
|
||||
<div className="card-row m0">
|
||||
{field.value.map((t, idx) => (
|
||||
<CardText key={`card-list-text-${idx}`} value={t} {...t} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
) : null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function renderRow(row) {
|
||||
return (
|
||||
<div className="card-row" key={hash(row)}>
|
||||
{row.map((field) => (
|
||||
<span key={hash(field)}>{renderField(field)}</span>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: render afterCaret appropriately from props
|
||||
sources = [];
|
||||
|
||||
return (
|
||||
<li
|
||||
key={hash(content)}
|
||||
className={`event-card ${isSelected ? "selected" : ""}`}
|
||||
onClick={onSelect}
|
||||
>
|
||||
{content.map((row) => renderRow(row))}
|
||||
{isOpen && (
|
||||
<div className="card-bottomhalf">
|
||||
{sources.map(() => (
|
||||
<div className="card-row"></div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{sources.length > 0 ? renderCaret() : null}
|
||||
</li>
|
||||
);
|
||||
};
|
||||
@@ -1,9 +1,6 @@
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
generateCardLayout,
|
||||
Card,
|
||||
} from "@forensic-architecture/design-system/dist/react";
|
||||
import { generateCardLayout, Card } from "./Card";
|
||||
|
||||
import * as selectors from "../../selectors";
|
||||
import { getFilterIdxFromColorSet } from "../../common/utilities";
|
||||
@@ -70,6 +67,7 @@ class CardStack extends React.Component {
|
||||
return events.map((event, idx) => {
|
||||
const thisRef = React.createRef();
|
||||
this.refs[idx] = thisRef;
|
||||
console.log(event);
|
||||
|
||||
const content = generateTemplate({
|
||||
event,
|
||||
|
||||
86
src/components/controls/atoms/Button.js
Normal file
86
src/components/controls/atoms/Button.js
Normal file
@@ -0,0 +1,86 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
/**
|
||||
* Primary UI component for user interaction
|
||||
*/
|
||||
export const Button = ({
|
||||
primary,
|
||||
backgroundColor,
|
||||
borderRadius,
|
||||
size,
|
||||
label,
|
||||
normalCursor,
|
||||
...props
|
||||
}) => {
|
||||
const mode = primary ? "button--primary" : "button--secondary";
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className={[
|
||||
"button",
|
||||
`button--${size}`,
|
||||
mode,
|
||||
normalCursor ? "no-hover" : "",
|
||||
].join(" ")}
|
||||
style={{ backgroundColor: backgroundColor, borderRadius: borderRadius }}
|
||||
{...props}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
Button.propTypes = {
|
||||
/**
|
||||
* Is this the principal call to action on the page?
|
||||
*/
|
||||
primary: PropTypes.bool,
|
||||
/**
|
||||
* What background color to use
|
||||
*/
|
||||
backgroundColor: PropTypes.string,
|
||||
/**
|
||||
* How much rounded are they?
|
||||
*/
|
||||
borderRadius: PropTypes.string,
|
||||
/**
|
||||
* How large should the button be?
|
||||
*/
|
||||
size: PropTypes.oneOf(["small", "medium", "large"]),
|
||||
/**
|
||||
* Button contents
|
||||
*/
|
||||
label: PropTypes.string.isRequired,
|
||||
/**
|
||||
* Optional click handler
|
||||
*/
|
||||
onClick: PropTypes.func,
|
||||
};
|
||||
|
||||
Button.defaultProps = {
|
||||
backgroundColor: "red",
|
||||
borderRadius: "0%",
|
||||
primary: false,
|
||||
size: "medium",
|
||||
onClick: undefined,
|
||||
};
|
||||
|
||||
const CardButton = ({
|
||||
text,
|
||||
color = "#000",
|
||||
onClick = () => {},
|
||||
normalCursor,
|
||||
}) => (
|
||||
<Button
|
||||
size={"small"}
|
||||
backgroundColor={color}
|
||||
borderRadius={"12px"}
|
||||
primary={false}
|
||||
label={text}
|
||||
onClick={onClick}
|
||||
normalCursor={normalCursor}
|
||||
/>
|
||||
);
|
||||
|
||||
export default CardButton;
|
||||
15
src/components/controls/atoms/Caret.js
Normal file
15
src/components/controls/atoms/Caret.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from "react";
|
||||
|
||||
const CardCaret = ({ isOpen, toggle }) => {
|
||||
let classes = isOpen ? "arrow-down" : "arrow-down folded";
|
||||
|
||||
return (
|
||||
<div className="card-toggle" onClick={toggle}>
|
||||
<p>
|
||||
<i className={classes} />
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardCaret;
|
||||
12
src/components/controls/atoms/CustomField.js
Normal file
12
src/components/controls/atoms/CustomField.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
import marked from "marked";
|
||||
|
||||
// TODO could this be a security vulnerability?
|
||||
const CardCustomField = ({ title, value }) => (
|
||||
<div className="card-cell">
|
||||
{title ? <h4>{title}</h4> : null}
|
||||
<div dangerouslySetInnerHTML={{ __html: marked(`${value}`) }} />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default CardCustomField;
|
||||
61
src/components/controls/atoms/Media.js
Normal file
61
src/components/controls/atoms/Media.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import React, { useRef } from "react";
|
||||
import { useCallback } from "react";
|
||||
import { typeForPath } from "../../../common/utilities";
|
||||
|
||||
const TITLE_LENGTH = 50;
|
||||
// TODO should videos
|
||||
// - play inline
|
||||
// - appear zoomed out/in
|
||||
// - only show cover image and then lightbox when clicked
|
||||
// - show video control plane?
|
||||
// TODO landscape image doesn't fit in box properly
|
||||
const Media = ({ src, title }) => {
|
||||
const videoRef = useRef();
|
||||
const onVideoStart = useCallback(() => {
|
||||
return videoRef.current?.play();
|
||||
}, []);
|
||||
const onVideoStop = useCallback(() => {
|
||||
return videoRef.current?.pause();
|
||||
}, []);
|
||||
|
||||
const type = typeForPath(src);
|
||||
const formattedTitle =
|
||||
title && title.length > TITLE_LENGTH
|
||||
? `${title.slice(0, TITLE_LENGTH + 1)}...`
|
||||
: title;
|
||||
|
||||
switch (type) {
|
||||
case "Video":
|
||||
return (
|
||||
<div className="card-cell media">
|
||||
{title && <h4 title={title}>{formattedTitle}</h4>}
|
||||
<video
|
||||
onMouseEnter={onVideoStart}
|
||||
onMouseLeave={onVideoStop}
|
||||
ref={videoRef}
|
||||
// controls
|
||||
// controlsList="nodownload noremoteplayback"
|
||||
disablePictureInPicture
|
||||
>
|
||||
<source src={src} />
|
||||
</video>
|
||||
</div>
|
||||
);
|
||||
case "Image":
|
||||
return (
|
||||
<div className="card-cell media">
|
||||
{title && <h4 title={title}>{formattedTitle}</h4>}
|
||||
<div className="img-wrapper">
|
||||
<img
|
||||
src={src}
|
||||
alt="an inline photograph for the event card component"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export default Media;
|
||||
46
src/components/controls/atoms/Text.js
Normal file
46
src/components/controls/atoms/Text.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
const CardText = ({ title, value, hoverValue = null }) => {
|
||||
const [showHover, setShowHover] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="card-cell">
|
||||
{title ? <h4>{title}</h4> : null}
|
||||
<div
|
||||
style={{
|
||||
width: `fit-content`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
onMouseOver={() => hoverValue && setShowHover(true)}
|
||||
onMouseOut={() => hoverValue && setShowHover(false)}
|
||||
>
|
||||
{showHover ? (
|
||||
<span
|
||||
style={{
|
||||
pointerEvents: `none`,
|
||||
opacity: 0.8,
|
||||
}}
|
||||
>
|
||||
<em>{hoverValue}</em>
|
||||
</span>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
pointerEvents: `none`,
|
||||
display: `inline-block`,
|
||||
height: `1.1rem`,
|
||||
borderBottom: hoverValue && `1px rgb(235, 68, 62) dashed`,
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* {!showHover && value} */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardText;
|
||||
29
src/components/controls/atoms/Time.js
Normal file
29
src/components/controls/atoms/Time.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from "react";
|
||||
|
||||
import copy from "../../../common/data/copy.json";
|
||||
import { isNotNullNorUndefined } from "../../../common/utilities";
|
||||
|
||||
const CardTime = ({ title = "Timestamp", timelabel, language, precision }) => {
|
||||
const unknownLang = copy[language].cardstack.unknown_time;
|
||||
|
||||
if (isNotNullNorUndefined(timelabel)) {
|
||||
return (
|
||||
<div className="card-cell">
|
||||
{/* <i className="material-icons left">today</i> */}
|
||||
<h4>{title}</h4>
|
||||
{timelabel}
|
||||
{precision && precision !== "" ? ` - ${precision}` : null}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className="card-cell">
|
||||
{/* <i className="material-icons left">today</i> */}
|
||||
<h4>{title}</h4>
|
||||
{unknownLang}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default CardTime;
|
||||
@@ -34,14 +34,14 @@ class TimelineAxis extends React.Component {
|
||||
if (this.props.scaleX) {
|
||||
this.x0 = d3
|
||||
.axisBottom(this.props.scaleX)
|
||||
.ticks(10)
|
||||
.ticks(5)
|
||||
.tickPadding(0)
|
||||
.tickSize(contentHeight - TEXT_HEIGHT - marginTop)
|
||||
.tickFormat(d3.timeFormat(fstFmt));
|
||||
|
||||
this.x1 = d3
|
||||
.axisBottom(this.props.scaleX)
|
||||
.ticks(10)
|
||||
.ticks(5)
|
||||
.tickPadding(marginTop)
|
||||
.tickSize(0)
|
||||
.tickFormat(d3.timeFormat(sndFmt));
|
||||
|
||||
37
src/scss/button.scss
Normal file
37
src/scss/button.scss
Normal file
@@ -0,0 +1,37 @@
|
||||
.button {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-weight: normal;
|
||||
border: 0;
|
||||
border-radius: 0em;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
outline: none;
|
||||
text-align: left;
|
||||
}
|
||||
.button--primary {
|
||||
color: $offwhite;
|
||||
background-color: $default;
|
||||
}
|
||||
.button--secondary {
|
||||
color: #333;
|
||||
background-color: transparent;
|
||||
box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 2px inset;
|
||||
}
|
||||
.button--small {
|
||||
font-size: 12px;
|
||||
padding: 10px 16px;
|
||||
margin: 0.6em 0.3em 0 0;
|
||||
}
|
||||
.button--medium {
|
||||
font-size: 14px;
|
||||
padding: 11px 20px;
|
||||
}
|
||||
.button--large {
|
||||
font-size: 16px;
|
||||
padding: 12px 24px;
|
||||
}
|
||||
|
||||
.no-hover {
|
||||
cursor: auto !important;
|
||||
}
|
||||
@@ -1,31 +1,35 @@
|
||||
.event-card {
|
||||
box-sizing: border-box;
|
||||
margin: 1px 0 0 0;
|
||||
margin: 2px 0;
|
||||
padding: 15px;
|
||||
border: 1px solid $black;
|
||||
transition: 0.2 ease;
|
||||
background: $midwhite;
|
||||
opacity: 0.92;
|
||||
color: $darkgrey;
|
||||
box-shadow: 0 19px 19px rgba(0, 0, 0, 0.3), 0 15px 12px rgba(0, 0, 0, 0.22);
|
||||
list-style-type: none;
|
||||
font-size: $large;
|
||||
line-height: $xxlarge;
|
||||
height: auto;
|
||||
opacity: 0.9;
|
||||
// height: auto;
|
||||
// opacity: 0.9;
|
||||
transition: background-color 0.4s;
|
||||
text-align: left;
|
||||
overflow-y: scroll;
|
||||
height: 100%;
|
||||
max-width: 400px;
|
||||
|
||||
&:hover {
|
||||
background: $lightwhite;
|
||||
transition: background-color 0.4s;
|
||||
cursor: pointer;
|
||||
// cursor: pointer;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-bottom: 0;
|
||||
margin-right: 5px;
|
||||
text-transform: uppercase;
|
||||
font-size: $xsmall;
|
||||
font-size: $small;
|
||||
color: $darkwhite;
|
||||
font-weight: 100;
|
||||
font-weight: 800;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
@@ -36,27 +40,23 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
font-size: $normal;
|
||||
color: $darkwhite;
|
||||
margin-right: 5px;
|
||||
.card-row,
|
||||
.card-col,
|
||||
.card-cell {
|
||||
margin: 5px 3px 5px 0px;
|
||||
&.m0 {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card-row,
|
||||
.card-col {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 5px 0 10px 0;
|
||||
padding-bottom: 10px;
|
||||
|
||||
.card-cell {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
h4 {
|
||||
min-width: 80px;
|
||||
max-width: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-col {
|
||||
@@ -72,23 +72,19 @@
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
padding: 8px 15px;
|
||||
border-left: 5px solid $darkgrey;
|
||||
padding: 5px 10px;
|
||||
border-left: 3px solid $darkgrey;
|
||||
background: linear-gradient(to right, $darkgrey 50%, transparent 50%);
|
||||
background-size: 200% 100%;
|
||||
background-position: right bottom;
|
||||
margin-left: -16px;
|
||||
margin-right: -16px;
|
||||
|
||||
&:hover {
|
||||
background-color: $darkgrey;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
.material-icons {
|
||||
color: white;
|
||||
}
|
||||
|
||||
background-position: left bottom;
|
||||
transition: all 2s ease;
|
||||
transition: all 1s ease-in;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +94,13 @@
|
||||
font-size: 24px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.source-type {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.card-cell {
|
||||
@@ -177,6 +180,57 @@
|
||||
}
|
||||
}
|
||||
|
||||
.media {
|
||||
display: flex;
|
||||
max-height: 350px;
|
||||
// justify-content: center;
|
||||
flex-direction: column;
|
||||
cursor: pointer;
|
||||
|
||||
.img-wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
img {
|
||||
// width: auto;
|
||||
// height: 100%;
|
||||
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
object-fit: cover;
|
||||
// width: 100%;
|
||||
// height: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
video {
|
||||
width: 100%;
|
||||
padding-bottom: 10px;
|
||||
user-select: none;
|
||||
&:focus {
|
||||
outline: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
video::-webkit-media-controls-panel {
|
||||
// remove Chrome's gradient
|
||||
background-image: none !important;
|
||||
filter: brightness(0.9);
|
||||
display: flex;
|
||||
align-self: flex-end;
|
||||
// flex-basis: 35px;
|
||||
background-color: rgba($red, 0.6);
|
||||
}
|
||||
|
||||
/* Could Use thise as well for Individual Controls */
|
||||
video::-webkit-media-controls-play-button {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
video::-webkit-media-controls-timeline {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.category {
|
||||
margin-bottom: 5px;
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// @import 'burger';
|
||||
// @import 'card';
|
||||
@import "card";
|
||||
|
||||
.card-stack {
|
||||
position: absolute;
|
||||
top: $card-right;
|
||||
right: $card-right;
|
||||
max-height: calc(100% - 180px);
|
||||
max-height: calc(100% - 260px);
|
||||
height: auto;
|
||||
width: $card-width;
|
||||
overflow-y: scroll;
|
||||
|
||||
Reference in New Issue
Block a user