mirror of
https://github.com/filecoin-project/slate.git
synced 2024-09-20 02:37:09 +03:00
added markdown reader darkmode
This commit is contained in:
parent
eaad9756f3
commit
e70c4925e6
@ -283,7 +283,7 @@ class CarouselSidebarData extends React.Component {
|
|||||||
|
|
||||||
_handleDarkMode = async (e) => {
|
_handleDarkMode = async (e) => {
|
||||||
Events.dispatchCustomEvent({
|
Events.dispatchCustomEvent({
|
||||||
name: "slate-theme-toggle-darkmode",
|
name: "set-slate-theme",
|
||||||
detail: { darkmode: e.target.value },
|
detail: { darkmode: e.target.value },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -610,9 +610,6 @@ class CarouselSidebarData extends React.Component {
|
|||||||
<div css={STYLES_TEXT}>Dark mode</div>
|
<div css={STYLES_TEXT}>Dark mode</div>
|
||||||
<Toggle dark active={this.props?.theme?.darkmode} onChange={this._handleDarkMode} />
|
<Toggle dark active={this.props?.theme?.darkmode} onChange={this._handleDarkMode} />
|
||||||
</div>
|
</div>
|
||||||
<div style={{ color: Constants.system.darkGray, marginTop: 8 }}>
|
|
||||||
{this.props?.data?.settings?.darkMode ? "You're saving your eyes" : "RIP"}
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
) : null}
|
) : null}
|
||||||
{this.props.isOwner && type?.startsWith("video/") ? (
|
{this.props.isOwner && type?.startsWith("video/") ? (
|
||||||
|
@ -1,32 +1,28 @@
|
|||||||
import "isomorphic-fetch";
|
import "isomorphic-fetch";
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as Constants from "~/common/constants";
|
import * as Strings from "~/common/strings";
|
||||||
|
|
||||||
import { css } from "@emotion/react";
|
import { css } from "@emotion/react";
|
||||||
import { Markdown } from "~/components/system/components/Markdown";
|
import { Markdown } from "~/components/system/components/Markdown";
|
||||||
import { H1, H2, H3, H4, P, UL, OL, LI, Link } from "~/components/system/components/Typography";
|
import { H1, H2, H3, H4, P, UL, OL, LI, Link } from "~/components/system/components/Typography";
|
||||||
|
|
||||||
const STYLES_ASSET = (theme) => {
|
const STYLES_ASSET = (theme) => css`
|
||||||
console.log(theme.darkMode);
|
padding: 120px calc(32px + 16px + 8px);
|
||||||
return css`
|
position: relative;
|
||||||
padding: 120px calc(32px + 16px + 8px);
|
width: 100%;
|
||||||
position: relative;
|
height: 100%;
|
||||||
width: 100%;
|
overflow-y: scroll;
|
||||||
height: 100%;
|
will-change: transform;
|
||||||
overflow-y: scroll;
|
color: ${theme.darkmode ? theme.system.wallLight : theme.system.pitchBlack};
|
||||||
will-change: transform;
|
background-color: ${theme.darkmode ? theme.system.pitchBlack : theme.system.wallLight};
|
||||||
color: ${theme.darkmode ? Constants.system.white : "#000"};
|
`;
|
||||||
background-color: ${theme.darkmode ? "#000" : "#fff"};
|
|
||||||
`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const STYLES_BODY = css`
|
const STYLES_BODY = css`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
// 687px to ensure we have maximum 70ch per line
|
// 687px to ensure we have maximum 70ch per line
|
||||||
max-width: 687px;
|
max-width: 687px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|
||||||
& > *:first-child {
|
& > *:first-child {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
@ -71,7 +67,48 @@ const STYLES_IMG = css`
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default function MarkdownFrame({ url }) {
|
const STYLES_META = (theme) => css`
|
||||||
|
max-width: 687px;
|
||||||
|
margin: 0 auto;
|
||||||
|
font-size: 12px;
|
||||||
|
color: ${theme.darkmode ? theme.system.textGray : theme.system.gray70};
|
||||||
|
letter-spacing: 0.2px;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const STYLES_DEVIDER = (theme) => css`
|
||||||
|
position: sticky;
|
||||||
|
// Note(Amine): asset padding
|
||||||
|
top: -120px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
max-width: 687px;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-bottom: 58px;
|
||||||
|
background-color: ${theme.system.gray50};
|
||||||
|
transition: height 0.3s;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const STYLE_PROGRESS = (theme) => css`
|
||||||
|
width: 80%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: ${theme.darkmode ? "#fff" : "#000"};
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const STYLES_INTENT = (theme) => css`
|
||||||
|
width: 100%;
|
||||||
|
height: 8px;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
${theme.darkmode ? theme.system.pitchBlack : theme.system.wallLight} 0%,
|
||||||
|
${theme.darkmode ? "rgba(12, 12, 12, 0)" : "rgba(241, 240, 242, 0)"} 100%
|
||||||
|
);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default function MarkdownFrame({ url, date }) {
|
||||||
const [content, setContent] = React.useState("");
|
const [content, setContent] = React.useState("");
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@ -81,6 +118,11 @@ export default function MarkdownFrame({ url }) {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const ref = React.useRef();
|
||||||
|
const { handleScrollAnimation, percentage } = useScrollPosition({ ref });
|
||||||
|
|
||||||
|
const readTime = Math.round(content.split(" ").length / 150);
|
||||||
|
|
||||||
const remarkReactComponents = {
|
const remarkReactComponents = {
|
||||||
p: (props) => <P {...props} />,
|
p: (props) => <P {...props} />,
|
||||||
h1: (props) => <H1 {...props} />,
|
h1: (props) => <H1 {...props} />,
|
||||||
@ -102,10 +144,34 @@ export default function MarkdownFrame({ url }) {
|
|||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
|
onScroll={handleScrollAnimation}
|
||||||
|
ref={ref}
|
||||||
>
|
>
|
||||||
<article css={STYLES_BODY}>
|
<div>
|
||||||
<Markdown md={content} css={STYLES_BODY} options={{ remarkReactComponents }} />
|
<div css={STYLES_META}>
|
||||||
</article>
|
<span>{Strings.toDate(date)}</span> / <span>{readTime} min read</span>
|
||||||
|
</div>
|
||||||
|
<div css={STYLES_DEVIDER} style={{ height: percentage > 15 ? "4px" : "1px" }}>
|
||||||
|
<div
|
||||||
|
css={STYLE_PROGRESS}
|
||||||
|
style={{ width: `${percentage}%`, opacity: percentage < 15 ? 0 : 1 }}
|
||||||
|
/>
|
||||||
|
<div css={STYLES_INTENT} />
|
||||||
|
</div>
|
||||||
|
<article css={STYLES_BODY}>
|
||||||
|
<Markdown md={content} css={STYLES_BODY} options={{ remarkReactComponents }} />
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useScrollPosition = ({ ref }) => {
|
||||||
|
const [percentage, setPercentage] = React.useState(0);
|
||||||
|
const handleScrollAnimation = () => {
|
||||||
|
const percentage =
|
||||||
|
(100 * ref.current.scrollTop) / (ref.current.scrollHeight - ref.current.clientHeight);
|
||||||
|
setPercentage(percentage);
|
||||||
|
};
|
||||||
|
return { percentage, handleScrollAnimation };
|
||||||
|
};
|
||||||
|
@ -140,7 +140,7 @@ export default class SlateMediaObject extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.data.name.endsWith(".md")) {
|
if (this.props.data.name.endsWith(".md")) {
|
||||||
return <MarkdownFrame url={this.props.data.url} />;
|
return <MarkdownFrame date={this.props.data.date} url={this.props.data.url} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Validations.isPreviewableImage(type)) {
|
if (Validations.isPreviewableImage(type)) {
|
||||||
|
@ -4,15 +4,15 @@ import * as Constants from "~/common/constants";
|
|||||||
import { ThemeProvider as EmotionTP } from "@emotion/react";
|
import { ThemeProvider as EmotionTP } from "@emotion/react";
|
||||||
|
|
||||||
export default function ThemeProvider({ children }) {
|
export default function ThemeProvider({ children }) {
|
||||||
const [theme, setTheme] = React.useState({ darkmode: true });
|
const [theme, setTheme] = useLocalStorage("slate-theme", { darkmode: true });
|
||||||
const toggleDarkMode = (e) => setTheme((prev) => ({ ...prev, darkmode: e.detail.darkmode }));
|
const handleSlateTheme = (e) => setTheme((prev) => ({ ...prev, ...e.detail }));
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!window) return;
|
if (!window) return;
|
||||||
window.addEventListener("slate-theme-toggle-darkmode", toggleDarkMode);
|
window.addEventListener("set-slate-theme", handleSlateTheme);
|
||||||
return () => {
|
return () => {
|
||||||
if (!window) return;
|
if (!window) return;
|
||||||
window.removeEventListener("slate-theme-toggle-darkmode", toggleDarkMode);
|
window.removeEventListener("set-slate-theme", handleSlateTheme);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -34,3 +34,18 @@ export default function ThemeProvider({ children }) {
|
|||||||
</EmotionTP>
|
</EmotionTP>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useLocalStorage = (key, defaultValue) => {
|
||||||
|
const [value, setValue] = React.useState(defaultValue);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const cachedValue = localStorage.getItem(key);
|
||||||
|
if (cachedValue) setValue(JSON.parse(cachedValue));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
localStorage.setItem(key, JSON.stringify(value));
|
||||||
|
}, [key, value]);
|
||||||
|
|
||||||
|
return [value, setValue];
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user