Skip to content

Commit f2543c6

Browse files
authored
Merge pull request #704 from filecoin-project/@aminejv/font-object-preview
improvement: font object preview
2 parents e845211 + 6b9d178 commit f2543c6

File tree

11 files changed

+132
-12
lines changed

11 files changed

+132
-12
lines changed

components/core/DataView.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,7 @@ export default class DataView extends React.Component {
747747
url={Strings.getCIDGatewayURL(each.cid)}
748748
title={each.name || each.file}
749749
type={each.type}
750+
cid={each.cid}
750751
coverImage={each.coverImage}
751752
dataView={true}
752753
/>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import * as React from "react";
2+
3+
import { css } from "@emotion/react";
4+
import { useFont } from "../hooks";
5+
6+
const withView = (Component) => (props) => {
7+
const ref = React.useRef(null);
8+
9+
const [isIntersecting, setIntersecting] = React.useState(false);
10+
11+
const observer = new IntersectionObserver(([entry]) => {
12+
if (entry.isIntersecting) setIntersecting(true);
13+
});
14+
15+
React.useEffect(() => {
16+
observer.observe(ref.current);
17+
return () => {
18+
observer.disconnect();
19+
};
20+
}, []);
21+
22+
return <div ref={ref}>{isIntersecting ? <Component {...props} /> : null}</div>;
23+
};
24+
25+
const STYLES_LETTER = (theme) => css`
26+
overflow: hidden;
27+
font-size: ${theme.typescale.lvl8};
28+
@media (max-width: ${theme.sizes.tablet}px) {
29+
font-size: ${theme.typescale.lvl4};
30+
}
31+
@media (max-width: ${theme.sizes.mobile}px) {
32+
font-size: ${theme.typescale.lvl5};
33+
}
34+
`;
35+
36+
const FontObjectPreview = React.memo(
37+
({ url, cid, fallback }) => {
38+
const { isFontLoading, error, fontName } = useFont({ url, name: cid }, [cid]);
39+
if (error || isFontLoading) {
40+
return fallback;
41+
}
42+
return (
43+
<div style={{ fontFamily: fontName }}>
44+
<div css={STYLES_LETTER}>Aa</div>
45+
</div>
46+
);
47+
},
48+
(prevProps, nextProps) => prevProps.cid === nextProps.cid && prevProps.url == nextProps.url
49+
);
50+
export default withView(FontObjectPreview);

components/core/FontFrame/hooks.js

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,37 @@ import * as Content from "./Views/content";
55
import { generateNumberByStep } from "~/common/utilities";
66

77
export const useFont = ({ url, name }, deps) => {
8-
const [loading, setLoading] = React.useState(false);
8+
const [fetchState, setFetchState] = React.useState({ loading: false, error: null });
99
const prevName = React.useRef(name);
1010

1111
if (!window.$SLATES_LOADED_FONTS) window.$SLATES_LOADED_FONTS = [];
1212
const alreadyLoaded = window.$SLATES_LOADED_FONTS.includes(name);
1313

1414
React.useEffect(() => {
15-
if (alreadyLoaded) return;
15+
if (alreadyLoaded) {
16+
setFetchState((prev) => ({ ...prev, error: null }));
17+
return;
18+
}
1619

17-
setLoading(true);
20+
setFetchState((prev) => ({ ...prev, error: null, loading: true }));
1821
const customFonts = new FontFace(name, `url(${url})`);
19-
customFonts.load().then((loadedFont) => {
20-
document.fonts.add(loadedFont);
21-
prevName.current = name;
22-
setLoading(false);
22+
customFonts
23+
.load()
24+
.then((loadedFont) => {
25+
document.fonts.add(loadedFont);
26+
prevName.current = name;
2327

24-
window.$SLATES_LOADED_FONTS.push(name);
25-
});
28+
setFetchState((prev) => ({ ...prev, loading: false }));
29+
window.$SLATES_LOADED_FONTS.push(name);
30+
})
31+
.catch((err) => {
32+
setFetchState({ loading: false, error: err });
33+
});
2634
}, deps);
2735

2836
return {
29-
isFontLoading: loading,
37+
isFontLoading: fetchState.loading,
38+
error: fetchState.error,
3039
// NOTE(Amine): show previous font while we load the new one.
3140
fontName: alreadyLoaded ? name : prevName.current,
3241
};

components/core/FontFrame/index.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ const FontLoader = () => (
4444
<p>loading...</p>
4545
</div>
4646
);
47-
export default function FontFrame({ cid, url, ...props }) {
48-
const { isFontLoading, fontName } = useFont({ url, name: cid }, [cid]);
47+
export default function FontFrame({ cid, url, fallback, ...props }) {
48+
const { isFontLoading, error, fontName } = useFont({ url, name: cid }, [cid, url]);
49+
4950
const [
5051
currentState,
5152
{
@@ -65,6 +66,10 @@ export default function FontFrame({ cid, url, ...props }) {
6566
},
6667
] = useFontControls();
6768

69+
if (error) {
70+
return fallback;
71+
}
72+
6873
return (
6974
<div css={GET_STYLES_CONTAINER} style={{ fontFamily: fontName }} {...props}>
7075
<div css={STYLES_MOBILE_HIDDEN}>

components/core/SearchModal.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ const FilePreview = ({ file, slate, user, viewerId }) => {
274274
url={file.url ? file.url : Strings.getCIDGatewayURL(file.cid)}
275275
title={file.title || file.name || file.file}
276276
type={file.type}
277+
cid={file.cide}
277278
coverImage={file.coverImage}
278279
/>
279280
</div>

components/core/SlateLayout.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,7 @@ export class SlateLayout extends React.Component {
13101310
charCap={70}
13111311
type={this.state.items[i].type}
13121312
url={this.state.items[i].url}
1313+
cid={this.state.items[i].cid}
13131314
title={this.state.items[i].title || this.state.items[i].name}
13141315
coverImage={this.state.items[i].coverImage}
13151316
height={pos.h * unit}

components/core/SlateLayoutMobile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export class SlateLayoutMobile extends React.Component {
3939
type={item.type}
4040
url={item.url}
4141
title={item.title || item.name}
42+
cid={item.cid}
4243
coverImage={item.coverImage}
4344
style={{
4445
height: `calc(100vw - 48px)`,

components/core/SlateMediaObject.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ export default class SlateMediaObject extends React.Component {
161161
name={this.props.data.file || this.props.data.name}
162162
cid={this.props.data.cid}
163163
url={url}
164+
fallback={element}
164165
onClick={(e) => {
165166
e.stopPropagation();
166167
}}

components/core/SlateMediaObjectPreview.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import { css } from "@emotion/react";
88
import { FileTypeIcon } from "~/components/core/FileTypeIcon";
99
import { Blurhash } from "react-blurhash";
1010
import { isBlurhashValid } from "blurhash";
11+
import { endsWithAny } from "~/common/utilities";
12+
13+
import FontObjectPreview from "~/components/core/FontFrame/Views/FontObjectPreview";
1114

1215
const STYLES_IMAGE_CONTAINER = css`
1316
background-color: ${Constants.system.white};
@@ -189,6 +192,51 @@ export default class SlateMediaObjectPreview extends React.Component {
189192
style={{ color: Constants.system.textGray }}
190193
/>
191194
);
195+
196+
if (endsWithAny([".ttf", ".otf", ".woff", ".woff2"], this.props.title)) {
197+
return (
198+
<article
199+
css={STYLES_ENTITY}
200+
style={{
201+
...this.props.style,
202+
border: this.props.previewPanel ? `1px solid ${Constants.system.bgGray}` : "auto",
203+
}}
204+
>
205+
<FontObjectPreview
206+
url={this.props.url}
207+
cid={this.props.cid}
208+
fallback={
209+
<div style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>
210+
<img
211+
src="https://slate.textile.io/ipfs/bafkreib5mnvds3cpe7ot7ibrakmrnja2hv5tast3giiarpl5nun7jpdt5m"
212+
alt=""
213+
height={this.props.previewPanel ? "80" : "64"}
214+
/>
215+
<div style={{ position: "absolute" }}>{element}</div>
216+
</div>
217+
}
218+
/>
219+
{this.props.title && !this.props.iconOnly && !this.props.previewPanel ? (
220+
<div style={{ position: "absolute", bottom: 16, left: 16, width: "inherit" }}>
221+
<div css={STYLES_TITLE}>{title}</div>
222+
{extension ? (
223+
<div
224+
css={STYLES_TITLE}
225+
style={{
226+
fontSize: 12,
227+
color: Constants.system.textGrayLight,
228+
fontFamily: Constants.font.medium,
229+
}}
230+
>
231+
{extension}
232+
</div>
233+
) : null}
234+
</div>
235+
) : null}
236+
</article>
237+
);
238+
}
239+
192240
return (
193241
<article
194242
css={STYLES_ENTITY}

components/core/SlatePreviewBlock.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export class SlatePreviewRow extends React.Component {
7373
type={each.type}
7474
url={each.url}
7575
style={this.props.previewStyle}
76+
cid={each.cid}
7677
title={each.title || each.name}
7778
iconOnly={this.props.small}
7879
coverImage={each.coverImage}
@@ -358,6 +359,7 @@ export class SlatePreviewBlock extends React.Component {
358359
charCap={30}
359360
type={first.type}
360361
url={first.url}
362+
cid={first.cid}
361363
title={first.title || first.name}
362364
coverImage={first.coverImage}
363365
/>

0 commit comments

Comments
 (0)