Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
canifa_note
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
canifa_note
Commits
b4057109
Unverified
Commit
b4057109
authored
May 20, 2023
by
boojack
Committed by
GitHub
May 20, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: update memo detail page (#1682)
* feat: update memo detail page * chore: update
parent
04124a2a
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
144 additions
and
186 deletions
+144
-186
image.go
common/image.go
+0
-76
go.mod
go.mod
+3
-3
go.sum
go.sum
+20
-4
resource.go
server/resource.go
+37
-29
ArchivedMemo.tsx
web/src/components/ArchivedMemo.tsx
+2
-2
CreateResourceDialog.tsx
web/src/components/CreateResourceDialog.tsx
+24
-26
DailyMemo.tsx
web/src/components/DailyMemo.tsx
+2
-2
Memo.tsx
web/src/components/Memo.tsx
+15
-7
index.tsx
web/src/components/MemoEditor/index.tsx
+4
-0
MemoRelationListView.tsx
web/src/components/MemoRelationListView.tsx
+5
-0
MemoResourceListView.tsx
web/src/components/MemoResourceListView.tsx
+2
-2
ResourceCover.tsx
web/src/components/ResourceCover.tsx
+8
-1
ShareMemoDialog.tsx
web/src/components/ShareMemoDialog.tsx
+2
-2
DatePicker.tsx
web/src/components/kit/DatePicker.tsx
+1
-1
EmbedMemo.tsx
web/src/pages/EmbedMemo.tsx
+2
-2
MemoDetail.tsx
web/src/pages/MemoDetail.tsx
+17
-29
No files found.
common/image.go
deleted
100644 → 0
View file @
04124a2a
package
common
import
(
"bytes"
"fmt"
"image"
"image/jpeg"
"image/png"
"os"
"path/filepath"
"strings"
"github.com/disintegration/imaging"
)
const
(
ThumbnailDir
=
".thumbnail_cache"
ThumbnailSize
=
302
// Thumbnail size should be defined by frontend
)
func
ResizeImageFile
(
dst
,
src
string
,
mime
string
)
error
{
srcBytes
,
err
:=
os
.
ReadFile
(
src
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Failed to open %s: %s"
,
src
,
err
)
}
dstBytes
,
err
:=
ResizeImageBlob
(
srcBytes
,
ThumbnailSize
,
mime
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Failed to resise %s: %s"
,
src
,
err
)
}
err
=
os
.
MkdirAll
(
filepath
.
Dir
(
dst
),
os
.
ModePerm
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Failed to mkdir for %s: %s"
,
dst
,
err
)
}
err
=
os
.
WriteFile
(
dst
,
dstBytes
,
0666
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Failed to write %s: %s"
,
dst
,
err
)
}
return
nil
}
func
ResizeImageBlob
(
data
[]
byte
,
maxSize
int
,
mime
string
)
([]
byte
,
error
)
{
var
err
error
var
oldImage
image
.
Image
switch
strings
.
ToLower
(
mime
)
{
case
"image/jpeg"
:
oldImage
,
err
=
jpeg
.
Decode
(
bytes
.
NewReader
(
data
))
case
"image/png"
:
oldImage
,
err
=
png
.
Decode
(
bytes
.
NewReader
(
data
))
default
:
return
nil
,
fmt
.
Errorf
(
"mime %s is not support"
,
mime
)
}
if
err
!=
nil
{
return
nil
,
err
}
newImage
:=
imaging
.
Resize
(
oldImage
,
maxSize
,
0
,
imaging
.
NearestNeighbor
)
var
newBuffer
bytes
.
Buffer
switch
mime
{
case
"image/jpeg"
:
err
=
jpeg
.
Encode
(
&
newBuffer
,
newImage
,
nil
)
case
"image/png"
:
err
=
png
.
Encode
(
&
newBuffer
,
newImage
)
}
if
err
!=
nil
{
return
nil
,
err
}
return
newBuffer
.
Bytes
(),
nil
}
go.mod
View file @
b4057109
...
@@ -20,12 +20,12 @@ require (
...
@@ -20,12 +20,12 @@ require (
go.uber.org/zap v1.24.0
go.uber.org/zap v1.24.0
golang.org/x/crypto v0.1.0
golang.org/x/crypto v0.1.0
golang.org/x/exp v0.0.0-20230111222715-75897c7a292a
golang.org/x/exp v0.0.0-20230111222715-75897c7a292a
golang.org/x/mod v0.
6
.0
golang.org/x/mod v0.
8
.0
golang.org/x/net v0.7.0
golang.org/x/net v0.7.0
golang.org/x/oauth2 v0.5.0
golang.org/x/oauth2 v0.5.0
)
)
require golang.org/x/image v0.
0.0-20191009234506-e7c1f5e7dbb8
// indirect
require golang.org/x/image v0.
7.0
// indirect
require (
require (
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
...
@@ -69,7 +69,7 @@ require (
...
@@ -69,7 +69,7 @@ require (
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/text v0.
7
.0 // indirect
golang.org/x/text v0.
9
.0 // indirect
golang.org/x/time v0.1.0 // indirect
golang.org/x/time v0.1.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
google.golang.org/protobuf v1.28.1 // indirect
...
...
go.sum
View file @
b4057109
...
@@ -261,6 +261,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
...
@@ -261,6 +261,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
...
@@ -281,6 +282,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
...
@@ -281,6 +282,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
...
@@ -298,8 +300,9 @@ golang.org/x/exp v0.0.0-20230111222715-75897c7a292a h1:/YWeLOBWYV5WAQORVPkZF3Pq9
...
@@ -298,8 +300,9 @@ golang.org/x/exp v0.0.0-20230111222715-75897c7a292a h1:/YWeLOBWYV5WAQORVPkZF3Pq9
golang.org/x/exp v0.0.0-20230111222715-75897c7a292a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230111222715-75897c7a292a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw=
golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
...
@@ -321,8 +324,9 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
...
@@ -321,8 +324,9 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
...
@@ -354,6 +358,8 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
...
@@ -354,6 +358,8 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
...
@@ -377,6 +383,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
...
@@ -377,6 +383,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
...
@@ -414,18 +422,24 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
...
@@ -414,18 +422,24 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.
7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo
=
golang.org/x/text v0.
3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ
=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
...
@@ -478,6 +492,8 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
...
@@ -478,6 +492,8 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
...
...
server/resource.go
View file @
b4057109
...
@@ -15,6 +15,7 @@ import (
...
@@ -15,6 +15,7 @@ import (
"strings"
"strings"
"time"
"time"
"github.com/disintegration/imaging"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
"github.com/pkg/errors"
"github.com/usememos/memos/api"
"github.com/usememos/memos/api"
...
@@ -30,6 +31,9 @@ const (
...
@@ -30,6 +31,9 @@ const (
// This is unrelated to maximum upload size limit, which is now set through system setting.
// This is unrelated to maximum upload size limit, which is now set through system setting.
maxUploadBufferSizeBytes
=
32
<<
20
maxUploadBufferSizeBytes
=
32
<<
20
MebiByte
=
1024
*
1024
MebiByte
=
1024
*
1024
// thumbnailImagePath is the directory to store image thumbnails.
thumbnailImagePath
=
".thumbnail_cache"
)
)
var
fileKeyPattern
=
regexp
.
MustCompile
(
`\{[a-z]{1,9}\}`
)
var
fileKeyPattern
=
regexp
.
MustCompile
(
`\{[a-z]{1,9}\}`
)
...
@@ -163,14 +167,6 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -163,14 +167,6 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to copy file"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to copy file"
)
.
SetInternal
(
err
)
}
}
if
filetype
==
"image/jpeg"
||
filetype
==
"image/png"
{
thumbnailPath
:=
path
.
Join
(
s
.
Profile
.
Data
,
common
.
ThumbnailDir
,
publicID
)
err
:=
common
.
ResizeImageFile
(
thumbnailPath
,
filePath
,
filetype
)
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to generate thumbnail"
)
.
SetInternal
(
err
)
}
}
resourceCreate
=
&
api
.
ResourceCreate
{
resourceCreate
=
&
api
.
ResourceCreate
{
CreatorID
:
userID
,
CreatorID
:
userID
,
Filename
:
filename
,
Filename
:
filename
,
...
@@ -323,14 +319,12 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -323,14 +319,12 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
}
}
if
resource
.
InternalPath
!=
""
{
if
resource
.
InternalPath
!=
""
{
err
:=
os
.
Remove
(
resource
.
InternalPath
)
if
err
:=
os
.
Remove
(
resource
.
InternalPath
);
err
!=
nil
{
if
err
!=
nil
{
log
.
Warn
(
fmt
.
Sprintf
(
"failed to delete local file with path %s"
,
resource
.
InternalPath
),
zap
.
Error
(
err
))
log
.
Warn
(
fmt
.
Sprintf
(
"failed to delete local file with path %s"
,
resource
.
InternalPath
),
zap
.
Error
(
err
))
}
}
thumbnailPath
:=
path
.
Join
(
s
.
Profile
.
Data
,
common
.
ThumbnailDir
,
resource
.
PublicID
)
thumbnailPath
:=
path
.
Join
(
s
.
Profile
.
Data
,
thumbnailImagePath
,
resource
.
PublicID
)
err
=
os
.
Remove
(
thumbnailPath
)
if
err
:=
os
.
Remove
(
thumbnailPath
);
err
!=
nil
{
if
err
!=
nil
{
log
.
Warn
(
fmt
.
Sprintf
(
"failed to delete local thumbnail with path %s"
,
thumbnailPath
),
zap
.
Error
(
err
))
log
.
Warn
(
fmt
.
Sprintf
(
"failed to delete local thumbnail with path %s"
,
thumbnailPath
),
zap
.
Error
(
err
))
}
}
}
}
...
@@ -423,30 +417,44 @@ func (s *Server) registerResourcePublicRoutes(g *echo.Group) {
...
@@ -423,30 +417,44 @@ func (s *Server) registerResourcePublicRoutes(g *echo.Group) {
blob
:=
resource
.
Blob
blob
:=
resource
.
Blob
if
resource
.
InternalPath
!=
""
{
if
resource
.
InternalPath
!=
""
{
resourcePath
:=
resource
.
InternalPath
resourcePath
:=
resource
.
InternalPath
if
c
.
QueryParam
(
"thumbnail"
)
==
"1"
&&
(
resource
.
Type
==
"image/jpeg"
||
resource
.
Type
==
"image/png"
)
{
src
,
err
:=
os
.
Open
(
resourcePath
)
thumbnailPath
:=
path
.
Join
(
s
.
Profile
.
Data
,
common
.
ThumbnailDir
,
resource
.
PublicID
)
if
_
,
err
:=
os
.
Stat
(
thumbnailPath
);
err
==
nil
{
resourcePath
=
thumbnailPath
}
else
if
os
.
IsNotExist
(
err
)
{
err
:=
common
.
ResizeImageFile
(
thumbnailPath
,
resourcePath
,
resource
.
Type
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
fmt
.
Sprintf
(
"Failed to resize resource: %s"
,
resourcePath
))
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
fmt
.
Sprintf
(
"Failed to open the local resource: %s"
,
resourcePath
))
.
SetInternal
(
err
)
}
defer
src
.
Close
()
blob
,
err
=
io
.
ReadAll
(
src
)
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
fmt
.
Sprintf
(
"Failed to read the local resource: %s"
,
resourcePath
))
.
SetInternal
(
err
)
}
}
}
resourcePath
=
thumbnailPath
if
c
.
QueryParam
(
"thumbnail"
)
==
"1"
&&
common
.
HasPrefixes
(
resource
.
Type
,
"image/png"
,
"image/jpeg"
)
{
}
else
{
ext
:=
filepath
.
Ext
(
filename
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
fmt
.
Sprintf
(
"Failed to check resource thumbnail stat: %s"
,
thumbnailPath
))
.
SetInternal
(
err
)
thumbnailPath
:=
path
.
Join
(
s
.
Profile
.
Data
,
thumbnailImagePath
,
resource
.
PublicID
+
ext
)
if
_
,
err
:=
os
.
Stat
(
thumbnailPath
);
err
!=
nil
{
if
!
errors
.
Is
(
err
,
os
.
ErrNotExist
)
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
fmt
.
Sprintf
(
"Failed to check thumbnail image stat: %s"
,
thumbnailPath
))
.
SetInternal
(
err
)
}
reader
:=
bytes
.
NewReader
(
blob
)
src
,
err
:=
imaging
.
Decode
(
reader
)
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
fmt
.
Sprintf
(
"Failed to decode thumbnail image: %s"
,
thumbnailPath
))
.
SetInternal
(
err
)
}
thumbnailImage
:=
imaging
.
Resize
(
src
,
512
,
0
,
imaging
.
Lanczos
)
if
err
:=
imaging
.
Save
(
thumbnailImage
,
thumbnailPath
);
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
fmt
.
Sprintf
(
"Failed to resize thumbnail image: %s"
,
thumbnailPath
))
.
SetInternal
(
err
)
}
}
}
}
src
,
err
:=
os
.
Open
(
resource
Path
)
src
,
err
:=
os
.
Open
(
thumbnail
Path
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
fmt
.
Sprintf
(
"Failed to open the local resource: %s"
,
resource
Path
))
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
fmt
.
Sprintf
(
"Failed to open the local resource: %s"
,
thumbnail
Path
))
.
SetInternal
(
err
)
}
}
defer
src
.
Close
()
defer
src
.
Close
()
blob
,
err
=
io
.
ReadAll
(
src
)
blob
,
err
=
io
.
ReadAll
(
src
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
fmt
.
Sprintf
(
"Failed to read the local resource: %s"
,
resource
Path
))
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
fmt
.
Sprintf
(
"Failed to read the local resource: %s"
,
thumbnail
Path
))
.
SetInternal
(
err
)
}
}
}
}
...
...
web/src/components/ArchivedMemo.tsx
View file @
b4057109
...
@@ -4,7 +4,7 @@ import { useMemoStore } from "@/store/module";
...
@@ -4,7 +4,7 @@ import { useMemoStore } from "@/store/module";
import
{
getDateTimeString
}
from
"@/helpers/datetime"
;
import
{
getDateTimeString
}
from
"@/helpers/datetime"
;
import
useToggle
from
"@/hooks/useToggle"
;
import
useToggle
from
"@/hooks/useToggle"
;
import
MemoContent
from
"./MemoContent"
;
import
MemoContent
from
"./MemoContent"
;
import
MemoResource
s
from
"./MemoResources
"
;
import
MemoResource
ListView
from
"./MemoResourceListView
"
;
import
"@/less/memo.less"
;
import
"@/less/memo.less"
;
interface
Props
{
interface
Props
{
...
@@ -67,7 +67,7 @@ const ArchivedMemo: React.FC<Props> = (props: Props) => {
...
@@ -67,7 +67,7 @@ const ArchivedMemo: React.FC<Props> = (props: Props) => {
</
div
>
</
div
>
</
div
>
</
div
>
<
MemoContent
content=
{
memo
.
content
}
/>
<
MemoContent
content=
{
memo
.
content
}
/>
<
MemoResource
s
resourceList=
{
memo
.
resourceList
}
/>
<
MemoResource
ListView
resourceList=
{
memo
.
resourceList
}
/>
</
div
>
</
div
>
);
);
};
};
...
...
web/src/components/CreateResourceDialog.tsx
View file @
b4057109
import
{
Button
,
Input
,
Select
,
Option
,
Typography
,
List
,
ListItem
,
Autocomplete
,
Tooltip
}
from
"@mui/joy"
;
import
{
Button
,
Input
,
Select
,
Option
,
Typography
,
List
,
ListItem
,
Autocomplete
}
from
"@mui/joy"
;
import
React
,
{
useRef
,
useState
}
from
"react"
;
import
React
,
{
useRef
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
useTranslation
}
from
"react-i18next"
;
import
{
useTranslation
}
from
"react-i18next"
;
...
@@ -215,8 +215,7 @@ const CreateResourceDialog: React.FC<Props> = (props: Props) => {
...
@@ -215,8 +215,7 @@ const CreateResourceDialog: React.FC<Props> = (props: Props) => {
</
div
>
</
div
>
<
List
size=
"sm"
sx=
{
{
width
:
"100%"
}
}
>
<
List
size=
"sm"
sx=
{
{
width
:
"100%"
}
}
>
{
fileList
.
map
((
file
,
index
)
=>
(
{
fileList
.
map
((
file
,
index
)
=>
(
<
Tooltip
title=
{
file
.
name
}
key=
{
file
.
name
}
placement=
"top"
>
<
ListItem
key=
{
file
.
name
}
className=
"flex justify-between"
>
<
ListItem
className=
"flex justify-between"
>
<
Typography
noWrap
>
{
file
.
name
}
</
Typography
>
<
Typography
noWrap
>
{
file
.
name
}
</
Typography
>
<
div
className=
"flex gap-1"
>
<
div
className=
"flex gap-1"
>
<
button
<
button
...
@@ -239,7 +238,6 @@ const CreateResourceDialog: React.FC<Props> = (props: Props) => {
...
@@ -239,7 +238,6 @@ const CreateResourceDialog: React.FC<Props> = (props: Props) => {
</
button
>
</
button
>
</
div
>
</
div
>
</
ListItem
>
</
ListItem
>
</
Tooltip
>
))
}
))
}
</
List
>
</
List
>
</>
</>
...
...
web/src/components/DailyMemo.tsx
View file @
b4057109
import
{
getTimeString
}
from
"@/helpers/datetime"
;
import
{
getTimeString
}
from
"@/helpers/datetime"
;
import
MemoContent
from
"./MemoContent"
;
import
MemoContent
from
"./MemoContent"
;
import
MemoResource
s
from
"./MemoResources
"
;
import
MemoResource
ListView
from
"./MemoResourceListView
"
;
import
"@/less/daily-memo.less"
;
import
"@/less/daily-memo.less"
;
interface
Props
{
interface
Props
{
...
@@ -18,7 +18,7 @@ const DailyMemo: React.FC<Props> = (props: Props) => {
...
@@ -18,7 +18,7 @@ const DailyMemo: React.FC<Props> = (props: Props) => {
</
div
>
</
div
>
<
div
className=
"memo-container"
>
<
div
className=
"memo-container"
>
<
MemoContent
content=
{
memo
.
content
}
showFull=
{
true
}
/>
<
MemoContent
content=
{
memo
.
content
}
showFull=
{
true
}
/>
<
MemoResource
s
resourceList=
{
memo
.
resourceList
}
/>
<
MemoResource
ListView
resourceList=
{
memo
.
resourceList
}
/>
</
div
>
</
div
>
<
div
className=
"split-line"
></
div
>
<
div
className=
"split-line"
></
div
>
</
div
>
</
div
>
...
...
web/src/components/Memo.tsx
View file @
b4057109
...
@@ -12,11 +12,11 @@ import Divider from "./kit/Divider";
...
@@ -12,11 +12,11 @@ import Divider from "./kit/Divider";
import
{
showCommonDialog
}
from
"./Dialog/CommonDialog"
;
import
{
showCommonDialog
}
from
"./Dialog/CommonDialog"
;
import
Icon
from
"./Icon"
;
import
Icon
from
"./Icon"
;
import
MemoContent
from
"./MemoContent"
;
import
MemoContent
from
"./MemoContent"
;
import
MemoResources
from
"./MemoResources"
;
import
MemoResourceListView
from
"./MemoResourceListView"
;
import
MemoRelationListView
from
"./MemoRelationListView"
;
import
showShareMemo
from
"./ShareMemoDialog"
;
import
showShareMemo
from
"./ShareMemoDialog"
;
import
showPreviewImageDialog
from
"./PreviewImageDialog"
;
import
showPreviewImageDialog
from
"./PreviewImageDialog"
;
import
showChangeMemoCreatedTsDialog
from
"./ChangeMemoCreatedTsDialog"
;
import
showChangeMemoCreatedTsDialog
from
"./ChangeMemoCreatedTsDialog"
;
import
MemoRelationListView
from
"./MemoRelationListView"
;
import
"@/less/memo.less"
;
import
"@/less/memo.less"
;
interface
Props
{
interface
Props
{
...
@@ -39,9 +39,17 @@ const Memo: React.FC<Props> = (props: Props) => {
...
@@ -39,9 +39,17 @@ const Memo: React.FC<Props> = (props: Props) => {
const
isVisitorMode
=
userStore
.
isVisitorMode
()
||
readonly
;
const
isVisitorMode
=
userStore
.
isVisitorMode
()
||
readonly
;
useEffect
(()
=>
{
useEffect
(()
=>
{
Promise
.
all
(
memo
.
relationList
.
map
((
memoRelation
)
=>
memoCacheStore
.
getOrFetchMemoById
(
memoRelation
.
relatedMemoId
))).
then
((
memoList
)
=>
{
Promise
.
allSettled
(
memo
.
relationList
.
map
((
memoRelation
)
=>
memoCacheStore
.
getOrFetchMemoById
(
memoRelation
.
relatedMemoId
))).
then
(
(
results
)
=>
{
const
memoList
=
[];
for
(
const
result
of
results
)
{
if
(
result
.
status
===
"fulfilled"
)
{
memoList
.
push
(
result
.
value
);
}
}
setRelatedMemoList
(
uniqWith
(
memoList
,
isEqual
));
setRelatedMemoList
(
uniqWith
(
memoList
,
isEqual
));
});
}
);
},
[
memo
.
relationList
]);
},
[
memo
.
relationList
]);
useEffect
(()
=>
{
useEffect
(()
=>
{
...
@@ -271,13 +279,13 @@ const Memo: React.FC<Props> = (props: Props) => {
...
@@ -271,13 +279,13 @@ const Memo: React.FC<Props> = (props: Props) => {
onMemoContentClick=
{
handleMemoContentClick
}
onMemoContentClick=
{
handleMemoContentClick
}
onMemoContentDoubleClick=
{
handleMemoContentDoubleClick
}
onMemoContentDoubleClick=
{
handleMemoContentDoubleClick
}
/>
/>
<
MemoResource
s
resourceList=
{
memo
.
resourceList
}
/>
<
MemoResource
ListView
resourceList=
{
memo
.
resourceList
}
/>
{
!
showRelatedMemos
&&
<
MemoRelationListView
relationList=
{
memo
.
relationList
}
/>
}
{
!
showRelatedMemos
&&
<
MemoRelationListView
relationList=
{
memo
.
relationList
}
/>
}
</
div
>
</
div
>
{
showRelatedMemos
&&
relatedMemoList
.
length
>
0
&&
(
{
showRelatedMemos
&&
relatedMemoList
.
length
>
0
&&
(
<>
<>
<
p
className=
"
font-mono text-sm mt-4 mb-1 pl-4 opacity-6
0 flex flex-row items-center"
>
<
p
className=
"
text-sm mt-4 mb-1 pl-4 opacity-5
0 flex flex-row items-center"
>
<
Icon
.
Link
className=
"w-4 h-auto mr-1"
/>
<
Icon
.
Link
className=
"w-4 h-auto mr-1"
/>
<
span
>
Related memos
</
span
>
<
span
>
Related memos
</
span
>
</
p
>
</
p
>
...
...
web/src/components/MemoEditor/index.tsx
View file @
b4057109
...
@@ -88,6 +88,10 @@ const MemoEditor = () => {
...
@@ -88,6 +88,10 @@ const MemoEditor = () => {
prevEditorStateRef
.
current
=
editorState
;
prevEditorStateRef
.
current
=
editorState
;
},
[
editorState
.
editMemoId
]);
},
[
editorState
.
editMemoId
]);
useEffect
(()
=>
{
handleEditorFocus
();
},
[
editorStore
.
state
.
relationList
]);
const
handleKeyDown
=
(
event
:
React
.
KeyboardEvent
)
=>
{
const
handleKeyDown
=
(
event
:
React
.
KeyboardEvent
)
=>
{
if
(
!
editorRef
.
current
)
{
if
(
!
editorRef
.
current
)
{
return
;
return
;
...
...
web/src/components/MemoRelationListView.tsx
View file @
b4057109
...
@@ -20,6 +20,10 @@ const MemoRelationListView = (props: Props) => {
...
@@ -20,6 +20,10 @@ const MemoRelationListView = (props: Props) => {
fetchRelatedMemoList
();
fetchRelatedMemoList
();
},
[
relationList
]);
},
[
relationList
]);
const
handleGotoMemoDetail
=
(
memo
:
Memo
)
=>
{
window
.
open
(
`/m/
${
memo
.
id
}
`
,
"_blank"
);
};
return
(
return
(
<>
<>
{
relatedMemoList
.
length
>
0
&&
(
{
relatedMemoList
.
length
>
0
&&
(
...
@@ -29,6 +33,7 @@ const MemoRelationListView = (props: Props) => {
...
@@ -29,6 +33,7 @@ const MemoRelationListView = (props: Props) => {
<
div
<
div
key=
{
memo
.
id
}
key=
{
memo
.
id
}
className=
"w-auto flex flex-row justify-start items-center hover:bg-gray-100 dark:hover:bg-zinc-800 rounded text-sm p-1 text-gray-500 dark:text-gray-400 cursor-pointer"
className=
"w-auto flex flex-row justify-start items-center hover:bg-gray-100 dark:hover:bg-zinc-800 rounded text-sm p-1 text-gray-500 dark:text-gray-400 cursor-pointer"
onClick=
{
()
=>
handleGotoMemoDetail
(
memo
)
}
>
>
<
div
className=
"w-5 h-5 flex justify-center items-center shrink-0 bg-gray-100 dark:bg-zinc-800 rounded-full"
>
<
div
className=
"w-5 h-5 flex justify-center items-center shrink-0 bg-gray-100 dark:bg-zinc-800 rounded-full"
>
<
Icon
.
Link
className=
"w-3 h-auto"
/>
<
Icon
.
Link
className=
"w-3 h-auto"
/>
...
...
web/src/components/MemoResource
s
.tsx
→
web/src/components/MemoResource
ListView
.tsx
View file @
b4057109
...
@@ -17,7 +17,7 @@ const getDefaultProps = (): Props => {
...
@@ -17,7 +17,7 @@ const getDefaultProps = (): Props => {
};
};
};
};
const
MemoResource
s
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
MemoResource
ListView
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
{
className
,
resourceList
}
=
{
const
{
className
,
resourceList
}
=
{
...
getDefaultProps
(),
...
getDefaultProps
(),
...
props
,
...
props
,
...
@@ -75,4 +75,4 @@ const MemoResources: React.FC<Props> = (props: Props) => {
...
@@ -75,4 +75,4 @@ const MemoResources: React.FC<Props> = (props: Props) => {
);
);
};
};
export
default
MemoResource
s
;
export
default
MemoResource
ListView
;
web/src/components/ResourceCover.tsx
View file @
b4057109
...
@@ -2,6 +2,7 @@ import React from "react";
...
@@ -2,6 +2,7 @@ import React from "react";
import
Icon
from
"./Icon"
;
import
Icon
from
"./Icon"
;
import
{
getResourceUrl
}
from
"@/utils/resource"
;
import
{
getResourceUrl
}
from
"@/utils/resource"
;
import
showPreviewImageDialog
from
"./PreviewImageDialog"
;
import
showPreviewImageDialog
from
"./PreviewImageDialog"
;
import
SquareDiv
from
"./kit/SquareDiv"
;
import
"@/less/resource-cover.less"
;
import
"@/less/resource-cover.less"
;
interface
ResourceCoverProps
{
interface
ResourceCoverProps
{
...
@@ -40,7 +41,13 @@ const ResourceCover = ({ resource }: ResourceCoverProps) => {
...
@@ -40,7 +41,13 @@ const ResourceCover = ({ resource }: ResourceCoverProps) => {
switch
(
resourceType
)
{
switch
(
resourceType
)
{
case
"image/*"
:
case
"image/*"
:
return
(
return
(
<
img
className=
"resource-cover h-20 w-20"
src=
{
resourceUrl
+
"?thumbnail=1"
}
onClick=
{
()
=>
showPreviewImageDialog
(
resourceUrl
)
}
/>
<
SquareDiv
className=
"h-20 w-20 flex items-center justify-center overflow-clip"
>
<
img
className=
"max-w-full max-h-full object-cover shadow"
src=
{
resourceUrl
+
"?thumbnail=1"
}
onClick=
{
()
=>
showPreviewImageDialog
(
resourceUrl
)
}
/>
</
SquareDiv
>
);
);
case
"video/*"
:
case
"video/*"
:
return
<
Icon
.
FileVideo2
className=
"resource-cover"
/>;
return
<
Icon
.
FileVideo2
className=
"resource-cover"
/>;
...
...
web/src/components/ShareMemoDialog.tsx
View file @
b4057109
...
@@ -14,7 +14,7 @@ import useLoading from "@/hooks/useLoading";
...
@@ -14,7 +14,7 @@ import useLoading from "@/hooks/useLoading";
import
Icon
from
"./Icon"
;
import
Icon
from
"./Icon"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
MemoContent
from
"./MemoContent"
;
import
MemoContent
from
"./MemoContent"
;
import
MemoResource
s
from
"./MemoResources
"
;
import
MemoResource
ListView
from
"./MemoResourceListView
"
;
import
showEmbedMemoDialog
from
"./EmbedMemoDialog"
;
import
showEmbedMemoDialog
from
"./EmbedMemoDialog"
;
import
"@/less/share-memo-dialog.less"
;
import
"@/less/share-memo-dialog.less"
;
...
@@ -177,7 +177,7 @@ const ShareMemoDialog: React.FC<Props> = (props: Props) => {
...
@@ -177,7 +177,7 @@ const ShareMemoDialog: React.FC<Props> = (props: Props) => {
<
span
className=
"w-full px-6 pt-5 pb-2 text-sm text-gray-500"
>
{
memo
.
createdAtStr
}
</
span
>
<
span
className=
"w-full px-6 pt-5 pb-2 text-sm text-gray-500"
>
{
memo
.
createdAtStr
}
</
span
>
<
div
className=
"w-full px-6 text-base pb-4"
>
<
div
className=
"w-full px-6 text-base pb-4"
>
<
MemoContent
content=
{
memo
.
content
}
showFull=
{
true
}
/>
<
MemoContent
content=
{
memo
.
content
}
showFull=
{
true
}
/>
<
MemoResource
s
className=
"!grid-cols-2"
resourceList=
{
memo
.
resourceList
}
/>
<
MemoResource
ListView
className=
"!grid-cols-2"
resourceList=
{
memo
.
resourceList
}
/>
</
div
>
</
div
>
<
div
className=
"flex flex-row justify-between items-center w-full bg-gray-100 dark:bg-zinc-700 py-4 px-6"
>
<
div
className=
"flex flex-row justify-between items-center w-full bg-gray-100 dark:bg-zinc-700 py-4 px-6"
>
<
div
className=
"mr-2"
>
<
div
className=
"mr-2"
>
...
...
web/src/components/kit/DatePicker.tsx
View file @
b4057109
...
@@ -18,12 +18,12 @@ const DatePicker: React.FC<DatePickerProps> = (props: DatePickerProps) => {
...
@@ -18,12 +18,12 @@ const DatePicker: React.FC<DatePickerProps> = (props: DatePickerProps) => {
const
{
className
,
datestamp
,
handleDateStampChange
}
=
props
;
const
{
className
,
datestamp
,
handleDateStampChange
}
=
props
;
const
[
currentDateStamp
,
setCurrentDateStamp
]
=
useState
<
DateStamp
>
(
getMonthFirstDayDateStamp
(
datestamp
));
const
[
currentDateStamp
,
setCurrentDateStamp
]
=
useState
<
DateStamp
>
(
getMonthFirstDayDateStamp
(
datestamp
));
const
[
countByDate
,
setCountByDate
]
=
useState
(
new
Map
());
const
[
countByDate
,
setCountByDate
]
=
useState
(
new
Map
());
const
currentUserId
=
useUserStore
().
getCurrentUserId
();
useEffect
(()
=>
{
useEffect
(()
=>
{
setCurrentDateStamp
(
getMonthFirstDayDateStamp
(
datestamp
));
setCurrentDateStamp
(
getMonthFirstDayDateStamp
(
datestamp
));
},
[
datestamp
]);
},
[
datestamp
]);
const
currentUserId
=
useUserStore
().
getCurrentUserId
();
useEffect
(()
=>
{
useEffect
(()
=>
{
getMemoStats
(
currentUserId
).
then
(({
data
:
{
data
}
})
=>
{
getMemoStats
(
currentUserId
).
then
(({
data
:
{
data
}
})
=>
{
const
m
=
new
Map
();
const
m
=
new
Map
();
...
...
web/src/pages/EmbedMemo.tsx
View file @
b4057109
...
@@ -5,7 +5,7 @@ import { UNKNOWN_ID } from "@/helpers/consts";
...
@@ -5,7 +5,7 @@ import { UNKNOWN_ID } from "@/helpers/consts";
import
{
useMemoStore
}
from
"@/store/module"
;
import
{
useMemoStore
}
from
"@/store/module"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
MemoContent
from
"@/components/MemoContent"
;
import
MemoContent
from
"@/components/MemoContent"
;
import
MemoResource
s
from
"@/components/MemoResources
"
;
import
MemoResource
ListView
from
"@/components/MemoResourceListView
"
;
import
{
getDateTimeString
}
from
"@/helpers/datetime"
;
import
{
getDateTimeString
}
from
"@/helpers/datetime"
;
interface
State
{
interface
State
{
...
@@ -51,7 +51,7 @@ const EmbedMemo = () => {
...
@@ -51,7 +51,7 @@ const EmbedMemo = () => {
</
a
>
</
a
>
</
div
>
</
div
>
<
MemoContent
className=
"memo-content"
content=
{
state
.
memo
.
content
}
onMemoContentClick=
{
()
=>
undefined
}
/>
<
MemoContent
className=
"memo-content"
content=
{
state
.
memo
.
content
}
onMemoContentClick=
{
()
=>
undefined
}
/>
<
MemoResource
s
resourceList=
{
state
.
memo
.
resourceList
}
/>
<
MemoResource
ListView
resourceList=
{
state
.
memo
.
resourceList
}
/>
</
div
>
</
div
>
</
main
>
</
main
>
)
}
)
}
...
...
web/src/pages/MemoDetail.tsx
View file @
b4057109
...
@@ -3,8 +3,9 @@ import { toast } from "react-hot-toast";
...
@@ -3,8 +3,9 @@ import { toast } from "react-hot-toast";
import
{
useTranslation
}
from
"react-i18next"
;
import
{
useTranslation
}
from
"react-i18next"
;
import
{
Link
,
useLocation
,
useParams
}
from
"react-router-dom"
;
import
{
Link
,
useLocation
,
useParams
}
from
"react-router-dom"
;
import
{
UNKNOWN_ID
}
from
"@/helpers/consts"
;
import
{
UNKNOWN_ID
}
from
"@/helpers/consts"
;
import
{
useGlobalStore
,
useMemoStore
,
useUserStore
}
from
"@/store/module"
;
import
{
useGlobalStore
,
useMemoStore
}
from
"@/store/module"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
Icon
from
"@/components/Icon"
;
import
Memo
from
"@/components/Memo"
;
import
Memo
from
"@/components/Memo"
;
interface
State
{
interface
State
{
...
@@ -17,7 +18,6 @@ const MemoDetail = () => {
...
@@ -17,7 +18,6 @@ const MemoDetail = () => {
const
location
=
useLocation
();
const
location
=
useLocation
();
const
globalStore
=
useGlobalStore
();
const
globalStore
=
useGlobalStore
();
const
memoStore
=
useMemoStore
();
const
memoStore
=
useMemoStore
();
const
userStore
=
useUserStore
();
const
[
state
,
setState
]
=
useState
<
State
>
({
const
[
state
,
setState
]
=
useState
<
State
>
({
memo
:
{
memo
:
{
id
:
UNKNOWN_ID
,
id
:
UNKNOWN_ID
,
...
@@ -25,7 +25,6 @@ const MemoDetail = () => {
...
@@ -25,7 +25,6 @@ const MemoDetail = () => {
});
});
const
loadingState
=
useLoading
();
const
loadingState
=
useLoading
();
const
customizedProfile
=
globalStore
.
state
.
systemStatus
.
customizedProfile
;
const
customizedProfile
=
globalStore
.
state
.
systemStatus
.
customizedProfile
;
const
user
=
userStore
.
state
.
user
;
useEffect
(()
=>
{
useEffect
(()
=>
{
const
memoId
=
Number
(
params
.
memoId
);
const
memoId
=
Number
(
params
.
memoId
);
...
@@ -47,38 +46,27 @@ const MemoDetail = () => {
...
@@ -47,38 +46,27 @@ const MemoDetail = () => {
return
(
return
(
<
section
className=
"relative top-0 w-full h-full overflow-y-auto overflow-x-hidden bg-zinc-100 dark:bg-zinc-800"
>
<
section
className=
"relative top-0 w-full h-full overflow-y-auto overflow-x-hidden bg-zinc-100 dark:bg-zinc-800"
>
<
div
className=
"relative w-full min-h-full mx-auto flex flex-col justify-start items-center pb-
8
"
>
<
div
className=
"relative w-full min-h-full mx-auto flex flex-col justify-start items-center pb-
6
"
>
<
div
className=
"
sticky top-0 z-10 max-w-2xl w-full min-h-full flex flex-row justify-between
items-center px-4 py-2 mt-2 bg-zinc-100 dark:bg-zinc-800"
>
<
div
className=
"
max-w-2xl w-full flex flex-row justify-center
items-center px-4 py-2 mt-2 bg-zinc-100 dark:bg-zinc-800"
>
<
div
className=
"flex flex-row justify-start items-center"
>
<
div
className=
"flex flex-row justify-start items-center"
>
<
img
className=
"h-10 w-auto rounded-lg mr-2"
src=
{
customizedProfile
.
logoUrl
}
alt=
""
/>
<
img
className=
"h-10 w-auto rounded-lg mr-2"
src=
{
customizedProfile
.
logoUrl
}
alt=
""
/>
<
p
className=
"text-4xl tracking-wide text-black dark:text-white"
>
{
customizedProfile
.
name
}
</
p
>
<
p
className=
"text-4xl tracking-wide text-black dark:text-white"
>
{
customizedProfile
.
name
}
</
p
>
</
div
>
</
div
>
<
div
className=
"action-button-container"
>
</
div
>
{
!
loadingState
.
isLoading
&&
(
{
!
loadingState
.
isLoading
&&
(
<>
<>
{
user
?
(
<
main
className=
"relative flex-grow max-w-2xl w-full min-h-full flex flex-col justify-start items-start px-4"
>
<
Memo
memo=
{
state
.
memo
}
readonly
showRelatedMemos
/>
</
main
>
<
div
className=
"mt-4 w-full flex flex-row justify-center items-center gap-2"
>
<
Link
<
Link
to=
"/"
to=
"/"
className=
"block text-gray-600 dark:text-gray-300 font-mono text-base py-1 border px-3 leading-8 rounded-xl
hover:opacity-80 hover:underline"
className=
"flex flex-row justify-center items-center text-gray-600 dark:text-gray-300 text-sm px-3
hover:opacity-80 hover:underline"
>
>
<
span
className=
"text-lg"
>
🏠
</
span
>
{
t
(
"router.back-to-home"
)
}
<
Icon
.
Home
className=
"w-4 h-auto mr-1 -mt-0.5"
/
>
{
t
(
"router.back-to-home"
)
}
</
Link
>
</
Link
>
)
:
(
<
Link
to=
"/auth"
className=
"block text-gray-600 dark:text-gray-300 font-mono text-base py-1 border px-3 leading-8 rounded-xl hover:opacity-80 hover:underline"
>
<
span
className=
"text-lg"
>
👉
</
span
>
{
t
(
"common.sign-in"
)
}
</
Link
>
)
}
</>
)
}
</
div
>
</
div
>
</
div
>
</>
{
!
loadingState
.
isLoading
&&
(
<
main
className=
"relative flex-grow max-w-2xl w-full min-h-full flex flex-col justify-start items-start px-4"
>
<
Memo
memo=
{
state
.
memo
}
readonly
showRelatedMemos
/>
</
main
>
)
}
)
}
</
div
>
</
div
>
</
section
>
</
section
>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment