mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-26 10:34:09 +03:00
added standalone file page and edited share modal to use it
This commit is contained in:
parent
dd386ba452
commit
d9e2c89659
@ -4,14 +4,19 @@ import { css } from "@emotion/react";
|
|||||||
|
|
||||||
/* TYPOGRAPHY */
|
/* TYPOGRAPHY */
|
||||||
|
|
||||||
|
export const OVERFLOW_ELLIPSIS = css`
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
`;
|
||||||
|
|
||||||
export const LINK = css`
|
export const LINK = css`
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: ${Constants.system.blue};
|
color: ${Constants.semantic.textBlack};
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: 200ms ease color;
|
|
||||||
|
|
||||||
:visited {
|
:visited {
|
||||||
color: ${Constants.system.blue};
|
color: ${Constants.semantic.textBlack};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -166,3 +166,7 @@ export const getImageUrlIfExists = (file, sizeLimit = null) => {
|
|||||||
return file.linkImage;
|
return file.linkImage;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getUserDisplayName = (user) => {
|
||||||
|
return user.name || `@${user.username}`;
|
||||||
|
};
|
||||||
|
@ -17,7 +17,6 @@ import * as Environment from "~/common/environment";
|
|||||||
// Scenes each have an ID and can be navigated to with _handleAction
|
// Scenes each have an ID and can be navigated to with _handleAction
|
||||||
import SceneError from "~/scenes/SceneError";
|
import SceneError from "~/scenes/SceneError";
|
||||||
import SceneEditAccount from "~/scenes/SceneEditAccount";
|
import SceneEditAccount from "~/scenes/SceneEditAccount";
|
||||||
import SceneFile from "~/scenes/SceneFile";
|
|
||||||
import SceneFilesFolder from "~/scenes/SceneFilesFolder";
|
import SceneFilesFolder from "~/scenes/SceneFilesFolder";
|
||||||
import SceneSettings from "~/scenes/SceneSettings";
|
import SceneSettings from "~/scenes/SceneSettings";
|
||||||
import SceneSlates from "~/scenes/SceneSlates";
|
import SceneSlates from "~/scenes/SceneSlates";
|
||||||
@ -75,7 +74,6 @@ const SCENES = {
|
|||||||
NAV_DIRECTORY: <SceneDirectory />,
|
NAV_DIRECTORY: <SceneDirectory />,
|
||||||
NAV_PROFILE: <SceneProfile />,
|
NAV_PROFILE: <SceneProfile />,
|
||||||
NAV_DATA: <SceneFilesFolder />,
|
NAV_DATA: <SceneFilesFolder />,
|
||||||
// NAV_FILE: <SceneFile />,
|
|
||||||
NAV_SLATE: <SceneSlate />,
|
NAV_SLATE: <SceneSlate />,
|
||||||
NAV_API: <SceneSettingsDeveloper />,
|
NAV_API: <SceneSettingsDeveloper />,
|
||||||
NAV_SETTINGS: <SceneEditAccount />,
|
NAV_SETTINGS: <SceneEditAccount />,
|
||||||
|
@ -4,6 +4,7 @@ import * as Styles from "~/common/styles";
|
|||||||
import * as UserBehaviors from "~/common/user-behaviors";
|
import * as UserBehaviors from "~/common/user-behaviors";
|
||||||
import * as Strings from "~/common/strings";
|
import * as Strings from "~/common/strings";
|
||||||
import * as Environment from "~/common/environment";
|
import * as Environment from "~/common/environment";
|
||||||
|
import * as Utilities from "~/common/utilities";
|
||||||
|
|
||||||
import { ButtonPrimaryFull, PopoverNavigation } from "~/components/system";
|
import { ButtonPrimaryFull, PopoverNavigation } from "~/components/system";
|
||||||
import { css } from "@emotion/react";
|
import { css } from "@emotion/react";
|
||||||
@ -129,7 +130,7 @@ export class ApplicationUserControlsPopup extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
if (this.props.popup !== "profile") return null;
|
if (this.props.popup !== "profile") return null;
|
||||||
|
|
||||||
const username = this.props.viewer.name || `@${this.props.viewer.username}`;
|
const username = Utilities.getUserDisplayName(this.props.viewer);
|
||||||
const objectsLength = this.props.viewer.library.length;
|
const objectsLength = this.props.viewer.library.length;
|
||||||
const { stats } = this.props.viewer;
|
const { stats } = this.props.viewer;
|
||||||
|
|
||||||
|
@ -67,11 +67,9 @@ export default function LinkTag({ url, ...props }) {
|
|||||||
<System.P2
|
<System.P2
|
||||||
style={{
|
style={{
|
||||||
paddingRight: 8,
|
paddingRight: 8,
|
||||||
overflow: "hidden",
|
|
||||||
textOverflow: "ellipsis",
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
...props.style,
|
...props.style,
|
||||||
}}
|
}}
|
||||||
|
css={Styles.OVERFLOW_ELLIPSIS}
|
||||||
>
|
>
|
||||||
{url}
|
{url}
|
||||||
</System.P2>
|
</System.P2>
|
||||||
|
@ -9,13 +9,13 @@ import isEqual from "lodash/isEqual";
|
|||||||
import Dismissible from "~/components/core/Dismissible";
|
import Dismissible from "~/components/core/Dismissible";
|
||||||
|
|
||||||
const STYLES_AVATAR = css`
|
const STYLES_AVATAR = css`
|
||||||
display: inline-flex;
|
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: 50% 50%;
|
background-position: 50% 50%;
|
||||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
|
||||||
position: relative;
|
position: relative;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background-color: ${Constants.system.black};
|
background-color: ${Constants.system.black};
|
||||||
|
display: block;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const STYLES_AVATAR_ONLINE = css`
|
const STYLES_AVATAR_ONLINE = css`
|
||||||
|
@ -4,6 +4,7 @@ import * as SVG from "~/common/svg";
|
|||||||
import * as System from "~/components/system";
|
import * as System from "~/components/system";
|
||||||
import * as Styles from "~/common/styles";
|
import * as Styles from "~/common/styles";
|
||||||
import * as Jumpers from "~/components/system/components/GlobalCarousel/jumpers";
|
import * as Jumpers from "~/components/system/components/GlobalCarousel/jumpers";
|
||||||
|
import * as Utilities from "~/common/utilities";
|
||||||
|
|
||||||
import { css } from "@emotion/react";
|
import { css } from "@emotion/react";
|
||||||
import { Alert } from "~/components/core/Alert";
|
import { Alert } from "~/components/core/Alert";
|
||||||
@ -19,6 +20,7 @@ import { ModalPortal } from "~/components/core/ModalPortal";
|
|||||||
|
|
||||||
import SlateMediaObject from "~/components/core/SlateMediaObject";
|
import SlateMediaObject from "~/components/core/SlateMediaObject";
|
||||||
import LinkIcon from "~/components/core/LinkIcon";
|
import LinkIcon from "~/components/core/LinkIcon";
|
||||||
|
import ProfilePhoto from "~/components/core/ProfilePhoto";
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------------------------------
|
/* -------------------------------------------------------------------------------------------------
|
||||||
* Carousel Header
|
* Carousel Header
|
||||||
@ -79,6 +81,7 @@ const STYLES_ACTION_BUTTON = css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
function CarouselHeader({
|
function CarouselHeader({
|
||||||
|
isStandalone,
|
||||||
viewer,
|
viewer,
|
||||||
data,
|
data,
|
||||||
external,
|
external,
|
||||||
@ -295,11 +298,27 @@ function CarouselHeader({
|
|||||||
{file.isLink ? <VisitLinkButton file={file} /> : null}
|
{file.isLink ? <VisitLinkButton file={file} /> : null}
|
||||||
</div>
|
</div>
|
||||||
</AnimateSharedLayout>
|
</AnimateSharedLayout>
|
||||||
<div style={{ marginLeft: 80 }}>
|
{isStandalone ? (
|
||||||
<button onClick={onClose} css={STYLES_ACTION_BUTTON}>
|
<a href={`/${file.owner.username}`} css={Styles.LINK} style={{ marginLeft: 80 }}>
|
||||||
<SVG.Dismiss />
|
<div
|
||||||
</button>
|
style={{ gap: 8, maxWidth: "138px", justifyContent: "flex-end" }}
|
||||||
</div>
|
css={Styles.HORIZONTAL_CONTAINER_CENTERED}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<ProfilePhoto user={file.owner} style={{ borderRadius: "8px" }} size={20} />
|
||||||
|
</div>
|
||||||
|
<p css={[Styles.H5, Styles.OVERFLOW_ELLIPSIS]}>
|
||||||
|
{Utilities.getUserDisplayName(file.owner)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<div style={{ marginLeft: 80 }}>
|
||||||
|
<button onClick={onClose} css={STYLES_ACTION_BUTTON}>
|
||||||
|
<SVG.Dismiss />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</motion.nav>
|
</motion.nav>
|
||||||
</>
|
</>
|
||||||
@ -346,27 +365,71 @@ const STYLES_CAROUSEL_MOBILE_SLIDE_COUNT = css`
|
|||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function CarouselHeaderMobile({ current, total, onClose, onNextSlide, onPreviousSlide }) {
|
function CarouselHeaderMobile({
|
||||||
|
isStandalone,
|
||||||
|
file,
|
||||||
|
current,
|
||||||
|
total,
|
||||||
|
onClose,
|
||||||
|
onNextSlide,
|
||||||
|
onPreviousSlide,
|
||||||
|
}) {
|
||||||
|
const isPreviousButtonDisabled = current === 1;
|
||||||
|
const isNextButtonDisabled = current === total;
|
||||||
return (
|
return (
|
||||||
<nav css={STYLES_CAROUSEL_MOBILE_HEADER} style={{ justifyContent: "space-between" }}>
|
<nav css={STYLES_CAROUSEL_MOBILE_HEADER} style={{ justifyContent: "space-between" }}>
|
||||||
<div style={{ width: 76 }}>
|
{!isStandalone && (
|
||||||
<button css={STYLES_ACTION_BUTTON} onClick={onPreviousSlide}>
|
<>
|
||||||
<SVG.ChevronLeft width={16} height={16} />
|
<div style={{ width: 76 }}>
|
||||||
</button>
|
<button
|
||||||
<button style={{ marginLeft: 12 }} css={STYLES_ACTION_BUTTON} onClick={onNextSlide}>
|
css={STYLES_ACTION_BUTTON}
|
||||||
<SVG.ChevronRight width={16} height={16} />
|
disabled={isPreviousButtonDisabled}
|
||||||
</button>
|
style={isPreviousButtonDisabled ? { color: Constants.system.grayLight3 } : null}
|
||||||
</div>
|
onClick={onPreviousSlide}
|
||||||
|
>
|
||||||
|
<SVG.ChevronLeft width={16} height={16} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
style={
|
||||||
|
isNextButtonDisabled
|
||||||
|
? { color: Constants.system.grayLight3, marginLeft: 12 }
|
||||||
|
: {
|
||||||
|
marginLeft: 12,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disabled={isNextButtonDisabled}
|
||||||
|
css={STYLES_ACTION_BUTTON}
|
||||||
|
onClick={onNextSlide}
|
||||||
|
>
|
||||||
|
<SVG.ChevronRight width={16} height={16} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<System.H5 color="textGray" as="p" css={STYLES_CAROUSEL_MOBILE_SLIDE_COUNT}>
|
<System.H5 color="textGray" as="p" css={STYLES_CAROUSEL_MOBILE_SLIDE_COUNT}>
|
||||||
{current} / {total}
|
{current} / {total}
|
||||||
</System.H5>
|
</System.H5>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<div style={{ textAlign: "right" }}>
|
{isStandalone ? (
|
||||||
<button onClick={onClose} css={STYLES_ACTION_BUTTON}>
|
<div
|
||||||
<SVG.Dismiss />
|
style={{ gap: 8, maxWidth: "138px", justifyContent: "flex-end" }}
|
||||||
</button>
|
css={Styles.HORIZONTAL_CONTAINER_CENTERED}
|
||||||
</div>
|
>
|
||||||
|
<div>
|
||||||
|
<ProfilePhoto user={file.owner} style={{ borderRadius: "8px" }} size={20} />
|
||||||
|
</div>
|
||||||
|
<p css={[Styles.H5, Styles.OVERFLOW_ELLIPSIS]}>
|
||||||
|
{Utilities.getUserDisplayName(file.owner)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div style={{ textAlign: "right" }}>
|
||||||
|
<button onClick={onClose} css={STYLES_ACTION_BUTTON}>
|
||||||
|
<SVG.Dismiss />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -617,7 +680,6 @@ const STYLES_PREVIEW_WRAPPER = (theme) => css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export function CarouselContent({
|
export function CarouselContent({
|
||||||
carouselType,
|
|
||||||
objects,
|
objects,
|
||||||
index,
|
index,
|
||||||
data,
|
data,
|
||||||
@ -629,9 +691,6 @@ export function CarouselContent({
|
|||||||
}) {
|
}) {
|
||||||
const file = objects?.[index];
|
const file = objects?.[index];
|
||||||
|
|
||||||
let isRepost = false;
|
|
||||||
if (carouselType === "SLATE") isRepost = data?.ownerId !== file.ownerId;
|
|
||||||
|
|
||||||
useLockScroll();
|
useLockScroll();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -782,7 +841,7 @@ const STYLES_ROOT = (theme) => css`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export function GlobalCarousel({
|
export function GlobalCarousel({
|
||||||
carouselType,
|
isStandalone,
|
||||||
objects,
|
objects,
|
||||||
index,
|
index,
|
||||||
params,
|
params,
|
||||||
@ -797,7 +856,7 @@ export function GlobalCarousel({
|
|||||||
style,
|
style,
|
||||||
}) {
|
}) {
|
||||||
const file = objects?.[index];
|
const file = objects?.[index];
|
||||||
const isCarouselOpen = (carouselType || index > 0 || index <= objects.length) && !!file;
|
const isCarouselOpen = (index > 0 || index <= objects.length) && !!file;
|
||||||
|
|
||||||
useCarouselViaParams({ index, params, objects, onChange });
|
useCarouselViaParams({ index, params, objects, onChange });
|
||||||
|
|
||||||
@ -815,6 +874,8 @@ export function GlobalCarousel({
|
|||||||
<div css={STYLES_ROOT}>
|
<div css={STYLES_ROOT}>
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
<CarouselHeaderMobile
|
<CarouselHeaderMobile
|
||||||
|
isStandalone={isStandalone}
|
||||||
|
file={file}
|
||||||
current={index + 1}
|
current={index + 1}
|
||||||
total={objects.length}
|
total={objects.length}
|
||||||
onPreviousSlide={handlePrevious}
|
onPreviousSlide={handlePrevious}
|
||||||
@ -823,6 +884,7 @@ export function GlobalCarousel({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<CarouselHeader
|
<CarouselHeader
|
||||||
|
isStandalone={isStandalone}
|
||||||
viewer={viewer}
|
viewer={viewer}
|
||||||
external={external}
|
external={external}
|
||||||
isOwner={isOwner}
|
isOwner={isOwner}
|
||||||
@ -839,7 +901,6 @@ export function GlobalCarousel({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<CarouselContent
|
<CarouselContent
|
||||||
carouselType={carouselType}
|
|
||||||
objects={objects}
|
objects={objects}
|
||||||
index={index}
|
index={index}
|
||||||
data={data}
|
data={data}
|
||||||
|
@ -36,6 +36,12 @@ const getSlateURLFromViewer = ({ viewer, file }) => {
|
|||||||
return `${rootUrl}/${username}/${collection.slatename}?cid=${file.cid}`;
|
return `${rootUrl}/${username}/${collection.slatename}?cid=${file.cid}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getFileURL = ({ file }) => {
|
||||||
|
const rootUrl = window?.location?.origin;
|
||||||
|
|
||||||
|
return `${rootUrl}/_/object/${file.id}`;
|
||||||
|
};
|
||||||
|
|
||||||
const getSlateURLFromData = ({ data, file }) => {
|
const getSlateURLFromData = ({ data, file }) => {
|
||||||
const username = data?.user?.username;
|
const username = data?.user?.username;
|
||||||
const rootUrl = window?.location?.origin;
|
const rootUrl = window?.location?.origin;
|
||||||
@ -46,9 +52,7 @@ const getSlateURLFromData = ({ data, file }) => {
|
|||||||
function FileSharingButtons({ file, data, viewer }) {
|
function FileSharingButtons({ file, data, viewer }) {
|
||||||
const fileName = file?.name || file?.filename;
|
const fileName = file?.name || file?.filename;
|
||||||
const username = data?.user?.username || viewer?.username;
|
const username = data?.user?.username || viewer?.username;
|
||||||
const fileLink = data
|
const fileLink = getFileURL({ file });
|
||||||
? getSlateURLFromData({ data, file })
|
|
||||||
: getSlateURLFromViewer({ viewer, file });
|
|
||||||
const [copyState, setCopyState] = React.useState({ isCidCopied: false, isLinkCopied: false });
|
const [copyState, setCopyState] = React.useState({ isCidCopied: false, isLinkCopied: false });
|
||||||
|
|
||||||
const handleTwitterSharing = () =>
|
const handleTwitterSharing = () =>
|
||||||
@ -61,9 +65,8 @@ function FileSharingButtons({ file, data, viewer }) {
|
|||||||
window.open(`mailto: ?subject=${fileName} by ${username} on Slate&body=${fileLink}`, "_b");
|
window.open(`mailto: ?subject=${fileName} by ${username} on Slate&body=${fileLink}`, "_b");
|
||||||
};
|
};
|
||||||
|
|
||||||
const cidLink = Strings.getURLfromCID(file.cid);
|
|
||||||
const handleLinkCopy = () => (
|
const handleLinkCopy = () => (
|
||||||
Utilities.copyToClipboard(cidLink), setCopyState({ isLinkCopied: true })
|
Utilities.copyToClipboard(fileLink), setCopyState({ isLinkCopied: true })
|
||||||
);
|
);
|
||||||
const handleCidCopy = () => (
|
const handleCidCopy = () => (
|
||||||
Utilities.copyToClipboard(file.cid), setCopyState({ isCidCopied: true })
|
Utilities.copyToClipboard(file.cid), setCopyState({ isCidCopied: true })
|
||||||
@ -82,7 +85,7 @@ function FileSharingButtons({ file, data, viewer }) {
|
|||||||
<button css={STYLES_SHARING_BUTTON} onClick={handleLinkCopy}>
|
<button css={STYLES_SHARING_BUTTON} onClick={handleLinkCopy}>
|
||||||
<SVG.Link width={16} />
|
<SVG.Link width={16} />
|
||||||
<System.P2 style={{ marginLeft: 12 }}>
|
<System.P2 style={{ marginLeft: 12 }}>
|
||||||
{copyState.isLinkCopied ? "Copied" : "Copy CID link"}
|
{copyState.isLinkCopied ? "Copied" : "Copy link"}
|
||||||
</System.P2>
|
</System.P2>
|
||||||
</button>
|
</button>
|
||||||
<button css={STYLES_SHARING_BUTTON} onClick={handleCidCopy}>
|
<button css={STYLES_SHARING_BUTTON} onClick={handleCidCopy}>
|
||||||
|
99
pages/_/file.js
Normal file
99
pages/_/file.js
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import * as Constants from "~/common/constants";
|
||||||
|
import * as Strings from "~/common/strings";
|
||||||
|
import * as Events from "~/common/custom-events";
|
||||||
|
|
||||||
|
import { css } from "@emotion/react";
|
||||||
|
import { GlobalCarousel } from "~/components/system/components/GlobalCarousel";
|
||||||
|
import { ButtonPrimary } from "~/components/system/components/Buttons";
|
||||||
|
|
||||||
|
import Profile from "~/components/core/Profile";
|
||||||
|
import WebsitePrototypeWrapper from "~/components/core/WebsitePrototypeWrapper";
|
||||||
|
import WebsitePrototypeHeader from "~/components/core/WebsitePrototypeHeader";
|
||||||
|
import WebsitePrototypeFooter from "~/components/core/WebsitePrototypeFooter";
|
||||||
|
import CTATransition from "~/components/core/CTATransition";
|
||||||
|
|
||||||
|
const DEFAULT_IMAGE =
|
||||||
|
"https://slate.textile.io/ipfs/bafkreiaow45dlq5xaydaeqocdxvffudibrzh2c6qandpqkb6t3ahbvh6re";
|
||||||
|
|
||||||
|
export const getServerSideProps = async (context) => {
|
||||||
|
return {
|
||||||
|
props: { ...context.query },
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const STYLES_ROOT = css`
|
||||||
|
display: block;
|
||||||
|
grid-template-rows: auto 1fr auto;
|
||||||
|
font-size: 1rem;
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: ${Constants.semantic.bgLight};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default class ProfilePage extends React.Component {
|
||||||
|
state = {
|
||||||
|
visible: false,
|
||||||
|
page: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount = () => {
|
||||||
|
console.log(this.props.data);
|
||||||
|
// window.onpopstate = this._handleBackForward;
|
||||||
|
|
||||||
|
// if (!Strings.isEmpty(this.props.cid)) {
|
||||||
|
// let files = this.props.creator.library || [];
|
||||||
|
// let index = files.findIndex((object) => object.cid === this.props.cid);
|
||||||
|
// if (index !== -1) {
|
||||||
|
// Events.dispatchCustomEvent({
|
||||||
|
// name: "slate-global-open-carousel",
|
||||||
|
// detail: { index },
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
// _handleBackForward = (e) => {
|
||||||
|
// let page = window.history.state;
|
||||||
|
// this.setState({ page });
|
||||||
|
// Events.dispatchCustomEvent({ name: "slate-global-close-carousel", detail: {} });
|
||||||
|
// };
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const isMobile = this.props.isMobile;
|
||||||
|
|
||||||
|
const viewer = this.props.viewer;
|
||||||
|
const file = this.props.data;
|
||||||
|
const { filename: title, body: description } = this.props.data;
|
||||||
|
// const title = this.props.data
|
||||||
|
// ? this.props.creator.name
|
||||||
|
// ? `${this.props.creator.name} on Slate`
|
||||||
|
// : `@${this.props.creator.username} on Slate`
|
||||||
|
// : "404";
|
||||||
|
const url = `https://slate.host/${title}`;
|
||||||
|
// const description = this.props.creator.body;
|
||||||
|
const image = DEFAULT_IMAGE; //this.props.creator.photo;
|
||||||
|
// if (Strings.isEmpty(image)) {
|
||||||
|
// image = DEFAULT_IMAGE;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WebsitePrototypeWrapper title={title} description={description} url={url} image={image}>
|
||||||
|
<WebsitePrototypeHeader />
|
||||||
|
<div css={STYLES_ROOT}>
|
||||||
|
<GlobalCarousel
|
||||||
|
isStandalone
|
||||||
|
viewer={viewer}
|
||||||
|
objects={[file]}
|
||||||
|
onAction={() => {}}
|
||||||
|
isMobile={isMobile}
|
||||||
|
// params={page.params}
|
||||||
|
isOwner={viewer.id === file.ownerId}
|
||||||
|
index={0}
|
||||||
|
onChange={() => {}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<WebsitePrototypeFooter />
|
||||||
|
</WebsitePrototypeWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -310,7 +310,6 @@ export default class SlatePage extends React.Component {
|
|||||||
<div css={STYLES_SLATE}>
|
<div css={STYLES_SLATE}>
|
||||||
<GlobalCarousel
|
<GlobalCarousel
|
||||||
data={this.props.slate}
|
data={this.props.slate}
|
||||||
carouselType="SLATE"
|
|
||||||
viewer={this.props.viewer}
|
viewer={this.props.viewer}
|
||||||
objects={objects}
|
objects={objects}
|
||||||
isMobile={this.props.isMobile}
|
isMobile={this.props.isMobile}
|
||||||
|
@ -96,7 +96,6 @@ export default function SceneActivity({ page, viewer, external, onAction, ...pro
|
|||||||
</ScenePage>
|
</ScenePage>
|
||||||
|
|
||||||
<GlobalCarousel
|
<GlobalCarousel
|
||||||
carouselType="ACTIVITY"
|
|
||||||
viewer={viewer}
|
viewer={viewer}
|
||||||
objects={globalCarouselState.currentObjects}
|
objects={globalCarouselState.currentObjects}
|
||||||
index={globalCarouselState.currentCarousel}
|
index={globalCarouselState.currentCarousel}
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
import * as React from "react";
|
|
||||||
import * as Constants from "~/common/constants";
|
|
||||||
import * as SVG from "~/common/svg";
|
|
||||||
import * as Strings from "~/common/strings";
|
|
||||||
|
|
||||||
import { css } from "@emotion/react";
|
|
||||||
|
|
||||||
import WebsitePrototypeWrapper from "~/components/core/WebsitePrototypeWrapper";
|
|
||||||
import SlateMediaObject from "~/components/core/SlateMediaObject";
|
|
||||||
|
|
||||||
const STYLES_FLEX = css`
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100vh;
|
|
||||||
background-color: ${Constants.system.black};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const STYLES_TOP = css`
|
|
||||||
background: ${Constants.system.black};
|
|
||||||
border-bottom: 1px solid ${Constants.system.black};
|
|
||||||
color: ${Constants.system.white};
|
|
||||||
width: 100%;
|
|
||||||
padding: 12px 16px 12px 16px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const STYLES_LEFT = css`
|
|
||||||
min-width: 10%;
|
|
||||||
width: 100%;
|
|
||||||
padding-right: 16px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const STYLES_RIGHT = css`
|
|
||||||
flex-shrink: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 100%;
|
|
||||||
padding-top: 4px;
|
|
||||||
transition: 200ms ease color;
|
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
:hover {
|
|
||||||
color: ${Constants.system.blue};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const STYLES_BOTTOM = css`
|
|
||||||
background: ${Constants.system.black};
|
|
||||||
color: ${Constants.system.white};
|
|
||||||
padding: 12px 16px 12px 48px;
|
|
||||||
width: 100%;
|
|
||||||
flex-shrink: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const STYLES_PATH = css`
|
|
||||||
font-family: "mono";
|
|
||||||
color: ${Constants.system.white};
|
|
||||||
font-size: 12px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
user-select: none;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default class SceneFile extends React.Component {
|
|
||||||
render() {
|
|
||||||
const cid = this.props.data.cid;
|
|
||||||
const fileURL = Strings.getURLfromCID(cid);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<WebsitePrototypeWrapper
|
|
||||||
title={`${this.props.page.pageTitle} • Slate`}
|
|
||||||
url={`${Constants.hostname}${this.props.page.pathname}`}
|
|
||||||
>
|
|
||||||
<div css={STYLES_FLEX}>
|
|
||||||
<div css={STYLES_TOP}>
|
|
||||||
<div css={STYLES_LEFT}>
|
|
||||||
<a css={STYLES_PATH} href={fileURL} target="_blank">
|
|
||||||
{fileURL}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div css={STYLES_RIGHT}>
|
|
||||||
<SVG.Dismiss height="24px" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<SlateMediaObject file={this.props.data} />
|
|
||||||
</div>
|
|
||||||
</WebsitePrototypeWrapper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -36,7 +36,6 @@ export default function SceneFilesFolder({ viewer, page, onAction, isMobile }) {
|
|||||||
>
|
>
|
||||||
<ScenePage css={STYLES_SCENE_PAGE}>
|
<ScenePage css={STYLES_SCENE_PAGE}>
|
||||||
<GlobalCarousel
|
<GlobalCarousel
|
||||||
carouselType="DATA"
|
|
||||||
viewer={viewer}
|
viewer={viewer}
|
||||||
objects={objects}
|
objects={objects}
|
||||||
onAction={onAction}
|
onAction={onAction}
|
||||||
|
@ -465,7 +465,6 @@ class SlatePage extends React.Component {
|
|||||||
{objects && objects.length ? (
|
{objects && objects.length ? (
|
||||||
<>
|
<>
|
||||||
<GlobalCarousel
|
<GlobalCarousel
|
||||||
carouselType="SLATE"
|
|
||||||
viewer={this.props.viewer}
|
viewer={this.props.viewer}
|
||||||
objects={objects}
|
objects={objects}
|
||||||
data={this.props.data}
|
data={this.props.data}
|
||||||
|
35
server.js
35
server.js
@ -122,6 +122,41 @@ app.prepare().then(async () => {
|
|||||||
// });
|
// });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.get("/_/object/:id", async (req, res) => {
|
||||||
|
let isMobile = Window.isMobileBrowser(req.headers["user-agent"]);
|
||||||
|
let isMac = Window.isMac(req.headers["user-agent"]);
|
||||||
|
|
||||||
|
const fileId = req.params.id;
|
||||||
|
|
||||||
|
const file = await Data.getFileById({ id: fileId });
|
||||||
|
|
||||||
|
const id = Utilities.getIdFromCookie(req);
|
||||||
|
|
||||||
|
if (!file.isPublic && file.ownerId !== id) {
|
||||||
|
return res.redirect("/_/404");
|
||||||
|
}
|
||||||
|
|
||||||
|
let viewer = null;
|
||||||
|
if (id) {
|
||||||
|
viewer = await ViewerManager.getById({
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id && id === file.ownerId) {
|
||||||
|
file.owner = viewer;
|
||||||
|
} else {
|
||||||
|
file.owner = await Data.getUserById({ id: file.ownerId, sanitize: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.render(req, res, "/_/file", {
|
||||||
|
viewer,
|
||||||
|
isMobile,
|
||||||
|
isMac,
|
||||||
|
data: file,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
server.get("/_/:scene", async (req, res) => {
|
server.get("/_/:scene", async (req, res) => {
|
||||||
let isMobile = Window.isMobileBrowser(req.headers["user-agent"]);
|
let isMobile = Window.isMobileBrowser(req.headers["user-agent"]);
|
||||||
let isMac = Window.isMac(req.headers["user-agent"]);
|
let isMac = Window.isMac(req.headers["user-agent"]);
|
||||||
|
Loading…
Reference in New Issue
Block a user