feat: update memo resources style (#933)

* feat: update memo resources style

* chore: update
pull/935/head
boojack 2 years ago committed by GitHub
parent 805122f45c
commit 8c146aed68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,6 +1,7 @@
package server
import (
"bytes"
"encoding/json"
"fmt"
"io"
@ -267,18 +268,13 @@ func (s *Server) registerResourcePublicRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to fetch resource ID: %v", resourceID)).SetInternal(err)
}
resourceType := resource.Type
if strings.HasPrefix(resource.Type, "text") || strings.HasPrefix(resource.Type, "application") {
c.Response().Writer.Header().Set("Content-Type", echo.MIMETextPlain)
} else {
c.Response().Writer.Header().Set("Content-Type", resource.Type)
resourceType = echo.MIMETextPlain
}
c.Response().Writer.WriteHeader(http.StatusOK)
c.Response().Writer.Header().Set(echo.HeaderCacheControl, "max-age=31536000, immutable")
c.Response().Writer.Header().Set(echo.HeaderContentSecurityPolicy, "default-src 'self'")
if _, err := c.Response().Writer.Write(resource.Blob); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to write response").SetInternal(err)
}
return nil
return c.Stream(http.StatusOK, resourceType, bytes.NewReader(resource.Blob))
})
}

@ -21,7 +21,7 @@ const DailyMemo: React.FC<Props> = (props: Props) => {
</div>
<div className="memo-container">
<MemoContent content={memo.content} displayConfig={displayConfig} />
<MemoResources resourceList={memo.resourceList} style="col" />
<MemoResources resourceList={memo.resourceList} />
</div>
<div className="split-line"></div>
</div>

@ -1,23 +1,23 @@
import Image from "./Image";
import { absolutifyLink } from "../helpers/utils";
import Icon from "./Icon";
import SquareDiv from "./common/SquareDiv";
import showPreviewImageDialog from "./PreviewImageDialog";
import "../less/memo-resources.less";
interface Props {
resourceList: Resource[];
className?: string;
style?: "row" | "col";
}
const getDefaultProps = (): Props => {
return {
className: "",
style: "row",
resourceList: [],
};
};
const MemoResources: React.FC<Props> = (props: Props) => {
const { className, style, resourceList } = {
const { className, resourceList } = {
...getDefaultProps(),
...props,
};
@ -35,24 +35,39 @@ const MemoResources: React.FC<Props> = (props: Props) => {
return `/o/r/${resource.id}/${resource.filename}`;
});
const handleImageClick = (imgUrl: string) => {
const index = imgUrls.findIndex((url) => url === imgUrl);
showPreviewImageDialog(imgUrls, index);
};
return (
<div className={`resource-wrapper ${className || ""}`}>
{availableResourceList.length > 0 && (
<div className={`images-wrapper ${style}`}>
{availableResourceList.map((resource) => {
const url = `/o/r/${resource.id}/${resource.filename}`;
if (resource.type.startsWith("image")) {
return (
<Image className="memo-resource" key={resource.id} imgUrls={imgUrls} index={imgUrls.findIndex((item) => item === url)} />
);
} else if (resource.type.startsWith("video")) {
return <video className="memo-resource" controls key={resource.id} src={url} />;
} else {
return null;
}
})}
</div>
)}
<>
<div className={`resource-wrapper ${className || ""}`}>
{availableResourceList.length > 0 && (
<div className="images-wrapper">
{availableResourceList.map((resource) => {
const url = `/o/r/${resource.id}/${resource.filename}`;
if (resource.type.startsWith("image")) {
return (
<SquareDiv key={resource.id} className="memo-resource">
<img src={absolutifyLink(url)} onClick={() => handleImageClick(url)} decoding="async" loading="lazy" />
</SquareDiv>
);
} else if (resource.type.startsWith("video")) {
return (
<SquareDiv key={resource.id} className="memo-resource">
<video preload="metadata" controls key={resource.id}>
<source src={absolutifyLink(url)} type={resource.type} />
</video>
</SquareDiv>
);
} else {
return null;
}
})}
</div>
)}
</div>
<div className="other-resource-wrapper">
{otherResourceList.map((resource) => {
return (
@ -63,7 +78,7 @@ const MemoResources: React.FC<Props> = (props: Props) => {
);
})}
</div>
</div>
</>
);
};

@ -135,7 +135,7 @@ const ShareMemoDialog: React.FC<Props> = (props: Props) => {
<span className="time-text">{memo.createdAtStr}</span>
<div className="memo-content-wrapper">
<MemoContent content={memo.content} displayConfig={{ enableExpand: false }} />
<MemoResources style="col" resourceList={memo.resourceList} />
<MemoResources resourceList={memo.resourceList} />
</div>
<div className="watermark-container">
<div className="userinfo-container">

@ -0,0 +1,45 @@
import { useEffect, useRef } from "react";
interface Props {
children: React.ReactNode;
baseSide?: "width" | "height";
className?: string;
}
const SquareDiv: React.FC<Props> = (props: Props) => {
const { children, className } = props;
const baseSide = props.baseSide || "width";
const squareDivRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const adjustSquareSize = () => {
if (!squareDivRef.current) {
return;
}
if (baseSide === "width") {
const width = squareDivRef.current.clientWidth;
squareDivRef.current.style.height = width + "px";
} else {
const height = squareDivRef.current.clientHeight;
squareDivRef.current.style.width = height + "px";
}
};
adjustSquareSize();
window.addEventListener("resize", adjustSquareSize);
return () => {
window.removeEventListener("resize", adjustSquareSize);
};
}, []);
return (
<div ref={squareDivRef} className={`${[baseSide === "width" ? "w-full" : "h-full", className ?? ""].join(" ")}`}>
{children}
</div>
);
};
export default SquareDiv;

@ -21,5 +21,11 @@
.memo-content-text {
@apply mt-1;
}
> .resource-wrapper {
> .images-wrapper {
@apply !grid-cols-2;
}
}
}
}

@ -1,11 +1,11 @@
.page-wrapper.explore {
@apply relative top-0 w-full h-full overflow-y-auto overflow-x-hidden bg-zinc-100 dark:bg-zinc-800;
@apply w-full h-full overflow-y-auto overflow-x-hidden bg-zinc-100 dark:bg-zinc-800;
> .page-container {
@apply relative w-full min-h-full mx-auto flex flex-col justify-start items-center pb-8;
> .page-header {
@apply sticky top-0 z-10 max-w-2xl w-full min-h-full flex flex-row justify-between backdrop-blur-sm items-center px-4 sm:pr-6 pt-6 mb-2 ml-calc;
@apply sticky top-0 z-10 max-w-2xl w-full h-auto flex flex-row justify-between backdrop-blur-sm items-center px-4 sm:pr-6 pt-6 mb-2 ml-calc;
> .title-container {
@apply flex flex-row justify-start items-center;
@ -27,7 +27,7 @@
}
> .memos-wrapper {
@apply relative flex-grow max-w-2xl w-full min-h-full flex flex-col justify-start items-start px-4 sm:pr-6 ml-calc;
@apply relative flex-grow max-w-2xl w-full h-auto flex flex-col justify-start items-start px-4 sm:pr-6 ml-calc;
> .memo-container {
@apply flex flex-col justify-start items-start w-full p-4 mt-2 bg-white dark:bg-zinc-700 rounded-lg border border-white dark:border-zinc-800 hover:border-gray-200 dark:hover:border-zinc-600;

@ -1,5 +1,5 @@
.page-wrapper.home {
@apply relative top-0 w-full h-full overflow-y-auto overflow-x-hidden bg-zinc-100 dark:bg-zinc-800;
@apply w-full h-full overflow-y-auto overflow-x-hidden bg-zinc-100 dark:bg-zinc-800;
> .banner-wrapper {
@apply w-full flex flex-col justify-start items-center;

@ -2,54 +2,34 @@
@apply w-full flex flex-col justify-start items-start;
> .images-wrapper {
@apply w-full flex mt-2 pb-1;
@apply w-full grid grid-cols-2 sm:grid-cols-3 gap-2 mt-2;
> .memo-resource {
@apply w-auto h-auto shrink-0 grow-0 cursor-pointer rounded;
@apply shadow overflow-auto hide-scrollbar;
> img {
@apply rounded hover:shadow;
@apply cursor-pointer rounded min-h-full w-auto min-w-full object-cover;
}
}
&.row {
@apply flex-row justify-start items-start overflow-x-auto overflow-y-hidden;
> .memo-resource {
@apply max-w-xs h-auto max-h-40 mr-2 last:mr-0;
> img {
@apply w-auto max-h-40;
}
}
}
&.col {
@apply flex-col justify-start items-start;
> .memo-resource {
@apply w-full h-auto mb-2 last:mb-0;
> img {
@apply w-full h-auto shadow;
}
> video {
@apply cursor-pointer rounded w-full h-full object-contain bg-zinc-100 dark:bg-zinc-800;
}
}
}
}
> .other-resource-wrapper {
@apply w-full flex flex-row justify-start flex-wrap;
.other-resource-wrapper {
@apply w-full flex flex-row justify-start flex-wrap;
> .other-resource-container {
@apply mt-1 mr-1 max-w-full flex flex-row justify-start items-center flex-nowrap bg-gray-100 px-2 py-1 rounded cursor-pointer hover:bg-gray-200;
> .other-resource-container {
@apply mt-1 mr-1 max-w-full flex flex-row justify-start items-center flex-nowrap bg-gray-100 px-2 py-1 rounded cursor-pointer hover:bg-gray-200;
> .icon-img {
@apply w-4 h-auto mr-1 text-gray-500;
}
> .icon-img {
@apply w-4 h-auto mr-1 text-gray-500;
}
> .name-text {
@apply text-gray-500 text-sm max-w-xs truncate font-mono;
}
> .name-text {
@apply text-gray-500 text-sm max-w-xs truncate font-mono;
}
}
}

@ -47,13 +47,11 @@
> .memo-content-wrapper {
@apply w-full px-6 text-base pb-4;
}
> .images-container {
@apply w-full h-auto flex flex-col justify-start items-start px-6 pb-2;
> img {
@apply w-full h-auto mb-2 rounded;
> .resource-wrapper {
> .images-wrapper {
@apply !grid-cols-2;
}
}
}

Loading…
Cancel
Save