Skip to content
This repository was archived by the owner on Nov 8, 2022. It is now read-only.

Commit f2af8d7

Browse files
authored
feat(editor-export): image block workflow (#298)
* refactor(editor-export): single image workflow * refactor(editor-export): jiugongge(九宫格) image workflow * refactor(editor-export): gallery image workflow * refactor(editor-export): gallery minimap scroll ux * test(editor-export): invalid data test for image block
1 parent ff76a4f commit f2af8d7

File tree

13 files changed

+670
-32
lines changed

13 files changed

+670
-32
lines changed

lib/helper/converter/editor_to_html/class.ex

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,25 @@ defmodule Helper.Converter.EditorToHTML.Class do
6161
"align_center" => "align-center",
6262
"align_left" => "align-left",
6363
"align_right" => "align-right"
64+
},
65+
"image" => %{
66+
"wrapper" => "image-wrapper",
67+
"single_image_wrapper" => "single-image",
68+
"single_image" => "image-picture",
69+
"image_caption" => "image-caption",
70+
# "single_caption"
71+
# jiugongge
72+
"jiugongge_image_wrapper" => "jiugongge-image",
73+
"jiugongge_image_block" => "jiugongge-block",
74+
"jiugongge_image" => "jiugongge-block-image",
75+
# gallery
76+
"gallery_image_wrapper" => "gallery-image",
77+
"gallery_image_inner" => "gallery-image-inner",
78+
"gallery_image_block" => "gallery-block",
79+
"gallery_image" => "gallery-block-image",
80+
# minimap
81+
"gallery_minimap" => "gallery-minimap",
82+
"gallery_minimap_image" => "gallery-minimap-block-image"
6483
}
6584
}
6685
end
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
defmodule Helper.Converter.EditorToHTML.Frags.Image do
2+
@moduledoc """
3+
parse editor.js's block fragments, use for test too
4+
5+
see https://editorjs.io/
6+
"""
7+
import Helper.Validator.Guards, only: [g_none_empty_str: 1]
8+
9+
alias Helper.Converter.EditorToHTML.Class
10+
alias Helper.Types, as: T
11+
12+
@class get_in(Class.article(), ["image"])
13+
14+
@spec get_item(:single | :gallery | :jiugongge, T.editor_image_item()) :: T.html()
15+
def get_item(
16+
:single,
17+
%{
18+
"src" => src,
19+
"width" => width,
20+
"height" => height
21+
} = data
22+
)
23+
when g_none_empty_str(width) and g_none_empty_str(height) do
24+
caption = get_caption(data)
25+
26+
image_wrapper_class = @class["single_image_wrapper"]
27+
image_class = @class["single_image"]
28+
29+
~s(<div class="#{image_wrapper_class}">
30+
<a href=#{src} class="glightbox" data-glightbox="type:image;description: #{caption}">
31+
<img class="#{image_class}" style="width:#{width}; height:#{height}" src="#{src}" alt="image" />
32+
</a>
33+
</div>)
34+
end
35+
36+
def get_item(:single, %{"src" => src} = data) do
37+
caption = get_caption(data)
38+
39+
image_wrapper_class = @class["single_image_wrapper"]
40+
image_class = @class["single_image"]
41+
42+
~s(<div class="#{image_wrapper_class}">
43+
<a href=#{src} class="glightbox" data-glightbox="type:image;description: #{caption}">
44+
<img class="#{image_class}" src="#{src}" alt="image" />
45+
</a>
46+
</div>)
47+
end
48+
49+
def get_item(:jiugongge, %{"src" => src} = data) do
50+
caption = get_caption(data)
51+
# image_wrapper_class = @class["jiugongge-image"]
52+
53+
jiugongge_image_block_class = @class["jiugongge_image_block"]
54+
image_class = @class["jiugongge_image"]
55+
56+
~s(<div class="#{jiugongge_image_block_class}">
57+
<a href=#{src} class="glightbox" data-glightbox="type:image;description: #{caption}">
58+
<img class="#{image_class}" src="#{src}" alt="image" />
59+
</a>
60+
</div>)
61+
end
62+
63+
def get_item(:gallery, %{"src" => src, "index" => index} = data) do
64+
caption = get_caption(data)
65+
66+
gallery_image_block_class = @class["gallery_image_block"]
67+
image_class = @class["gallery_image"]
68+
69+
# IO.inspect(index, label: "index -> ")
70+
~s(<div class="#{gallery_image_block_class}">
71+
<a href=#{src} class="glightbox" data-glightbox="type:image;description: #{caption}">
72+
<img class="#{image_class}" src="#{src}" alt="image" data-index="#{index}" />
73+
</a>
74+
</div>)
75+
end
76+
77+
@spec get_minimap([T.editor_image_item()]) :: T.html()
78+
def get_minimap(items) do
79+
wrapper_class = @class["gallery_minimap"]
80+
81+
items_content =
82+
Enum.reduce(items, "", fn item, acc ->
83+
acc <> frag(:minimap_image, item)
84+
end)
85+
86+
~s(<div class="#{wrapper_class}">
87+
#{items_content}
88+
</div>)
89+
end
90+
91+
defp frag(:minimap_image, %{"src" => src, "index" => index}) do
92+
image_class = @class["gallery_minimap_image"]
93+
94+
~s(<img class="#{image_class}" src="#{src}" data-index="#{index}"/>)
95+
end
96+
97+
def get_caption(%{"caption" => caption}) when g_none_empty_str(caption), do: caption
98+
def get_caption(_), do: ""
99+
100+
def get_caption(:html, %{"caption" => caption}) when g_none_empty_str(caption) do
101+
image_caption = @class["image_caption"]
102+
~s(<div class="#{image_caption}">#{caption}</div>)
103+
end
104+
105+
def get_caption(:html, _), do: ""
106+
107+
# @spec frag(:checkbox, :text, String.t()) :: T.html()
108+
# def frag(:checkbox, :text, text) do
109+
# text_class = @class["checklist_text"]
110+
111+
# ~s(<div class="#{text_class}">
112+
# #{text}
113+
# </div>)
114+
# end
115+
116+
# defp svg(type) do
117+
# # workarround for https://github.com/rrrene/html_sanitize_ex/issues/48
118+
# svg_frag(type) |> String.replace(" viewBox=\"", " viewbox=\"")
119+
# end
120+
121+
# defp svg_frag(:checked) do
122+
# ~s(<svg t="1592049095081" width="20px" height="20px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9783"><path d="M853.333333 256L384 725.333333l-213.333333-213.333333" p-id="9784"></path></svg>)
123+
# end
124+
end

lib/helper/converter/editor_to_html/frontend_test/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
<meta name="description" content="The HTML5 Herald">
99
<meta name="author" content="SitePoint">
1010

11+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/glightbox/dist/css/glightbox.min.css" />
1112
<link rel="stylesheet" href="./styles.css?v=1.0">
1213
<div id="article"></div>
1314
</head>
1415

1516
<body>
17+
<script src="https://cdn.jsdelivr.net/gh/mcstudios/glightbox/dist/js/glightbox.min.js"></script>
1618
<script src="./script.js"></script>
1719
</body>
1820
</html>

lib/helper/converter/editor_to_html/frontend_test/script.js

Lines changed: 39 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/helper/converter/editor_to_html/frontend_test/styles.css

Lines changed: 136 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
11
body {
2-
border: 1px solid #ececec;
32
min-height: 80vh;
4-
margin: 20px 5vw;
3+
display: flex;
4+
justify-content: center;
5+
}
6+
7+
#article {
8+
width: 650px;
9+
border: 1px solid #ececec;
10+
}
11+
12+
.glightbox-clean .gslide-description {
13+
background: transparent !important;
14+
}
15+
.gdesc-inner {
16+
background-image: linear-gradient(transparent, #272727) !important;
17+
color: lightgrey;
18+
font-size: 15px;
19+
position: absolute;
20+
width: calc(100% - 39px);
21+
bottom: 0;
22+
left: -1px;
23+
word-break: break-all;
524
}
625

726
.article-viewer-wrapper {
@@ -366,3 +385,118 @@ td {
366385
}
367386

368387
/* quote block end */
388+
389+
/* image block */
390+
.article-viewer-wrapper .image-wrapper {
391+
position: relative;
392+
margin-top: 20px;
393+
margin-bottom: 20px;
394+
}
395+
396+
.article-viewer-wrapper .image-wrapper .single-image {
397+
display: flex;
398+
justify-content: center;
399+
width: 100%;
400+
height: 100%;
401+
}
402+
403+
.article-viewer-wrapper .image-wrapper .single-image .image-picture {
404+
max-width: 100%;
405+
display: block;
406+
z-index: 5;
407+
}
408+
409+
.article-viewer-wrapper .image-wrapper .image-caption {
410+
text-align: center;
411+
color: grey;
412+
margin-top: 15px;
413+
}
414+
415+
.article-viewer-wrapper .image-wrapper .jiugongge-image {
416+
display: flex;
417+
flex-wrap: wrap;
418+
width: 489px;
419+
max-height: 489px;
420+
margin: 0 auto;
421+
padding: 45px 0;
422+
}
423+
424+
.article-viewer-wrapper .image-wrapper .jiugongge-block {
425+
position: relative;
426+
display: flex;
427+
justify-content: center;
428+
align-items: center;
429+
width: 160px;
430+
height: 160px;
431+
border-radius: 2px;
432+
background: #efefef;
433+
margin-right: 3px;
434+
margin-bottom: 3px;
435+
}
436+
437+
.article-viewer-wrapper .image-wrapper a {
438+
width: 100%;
439+
height: 100%;
440+
}
441+
442+
.article-viewer-wrapper .image-wrapper .jiugongge-block-image {
443+
width: 100%;
444+
height: 100%;
445+
object-fit: cover;
446+
transition: all 0.25s;
447+
}
448+
449+
.article-viewer-wrapper .image-wrapper .gallery-image {
450+
width: 100%;
451+
max-height: 400px;
452+
overflow: hidden;
453+
}
454+
455+
.article-viewer-wrapper .image-wrapper .gallery-image-inner {
456+
display: flex;
457+
width: 100%;
458+
max-height: 400px;
459+
padding-bottom: 17px;
460+
overflow: scroll;
461+
}
462+
463+
.article-viewer-wrapper .image-wrapper .gallery-block {
464+
position: relative;
465+
border-radius: 2px;
466+
background: #efefef;
467+
margin-right: 5px;
468+
margin-bottom: 3px;
469+
width: auto;
470+
}
471+
472+
.article-viewer-wrapper .image-wrapper a {
473+
width: 100%;
474+
height: 100%;
475+
}
476+
477+
.article-viewer-wrapper .image-wrapper .gallery-block-image {
478+
width: auto;
479+
height: 400px;
480+
object-fit: cover;
481+
transition: all 0.25s;
482+
}
483+
484+
.article-viewer-wrapper .image-wrapper .gallery-minimap {
485+
display: flex;
486+
align-items: center;
487+
justify-content: center;
488+
width: 100%;
489+
height: 55px;
490+
margin-top: 6px;
491+
}
492+
493+
.article-viewer-wrapper .image-wrapper .gallery-minimap-block-image {
494+
width: 46px;
495+
height: 46px;
496+
margin-right: 6px;
497+
object-fit: contain;
498+
background: #f7f7f7;
499+
cursor: pointer;
500+
}
501+
502+
/* image block end */

0 commit comments

Comments
 (0)