iceholidays-frontend 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/iceholidays/frontend/_slick-theme.scss +194 -0
- data/app/assets/stylesheets/iceholidays/frontend/_slick.scss +100 -0
- data/app/assets/stylesheets/iceholidays/frontend/application.sass.scss +64 -4
- data/app/assets/stylesheets/iceholidays/frontend/common.scss +17 -2
- data/app/assets/stylesheets/iceholidays/frontend/layout.scss +1 -1
- data/app/assets/stylesheets/iceholidays/frontend/utils/_slick_overrides.scss +3 -0
- data/app/javascript/api-services/brochure-api.service.ts +17 -0
- data/app/javascript/api-services/posts-api.service.ts +47 -0
- data/app/javascript/interfaces/blog.interface.ts +8 -0
- data/app/javascript/react/App.tsx +1 -1
- data/app/javascript/react/components/Destinations.tsx +21 -10
- data/app/javascript/react/components/PriceDetails.tsx +6 -6
- data/app/javascript/react/components/Testimonials.tsx +4 -1
- data/app/javascript/react/components/shared/LocationDropdown.tsx +3 -1
- data/app/javascript/react/layouts/MainHeader.tsx +80 -32
- data/app/javascript/react/pages/AboutUsPage.tsx +4 -4
- data/app/javascript/react/pages/BlogPage.tsx +82 -66
- data/app/javascript/react/pages/BlogShowPage.tsx +50 -35
- data/app/javascript/react/pages/ListingPage.tsx +115 -85
- data/app/javascript/react/pages/ShowPage.tsx +124 -87
- data/app/javascript/react/widgets/FilterPills.tsx +21 -18
- data/config/routes.rb +1 -1
- data/lib/iceholidays/frontend/version.rb +1 -1
- data/public/iceholidays-assets/application.css +306 -11
- data/public/iceholidays-assets/application.js +161 -121
- data/public/iceholidays-assets/application.js.map +4 -4
- data/public/iceholidays-assets/images/TST Ribbon@2x.png +0 -0
- data/public/iceholidays-assets/images/TST Ribbon@3x.png +0 -0
- data/public/iceholidays-assets/images/TSTRibbon.png +0 -0
- metadata +11 -2
|
@@ -8,10 +8,11 @@ import { mdiFilterVariant } from "@mdi/js";
|
|
|
8
8
|
const LocationDropdown = (
|
|
9
9
|
props: {
|
|
10
10
|
locations:Location[];
|
|
11
|
+
initialValue:string;
|
|
11
12
|
selectLocation;
|
|
12
13
|
}
|
|
13
14
|
) => {
|
|
14
|
-
const { locations } = props;
|
|
15
|
+
const { locations, initialValue } = props;
|
|
15
16
|
|
|
16
17
|
return (
|
|
17
18
|
<div className="location-dropdown">
|
|
@@ -20,6 +21,7 @@ const LocationDropdown = (
|
|
|
20
21
|
suffixIcon={<Icon path={mdiFilterVariant} size="18px" />}
|
|
21
22
|
variant="borderless"
|
|
22
23
|
defaultValue="china"
|
|
24
|
+
value={initialValue}
|
|
23
25
|
options={locations.map((location) => ({label: location.name, value: location.id}))}
|
|
24
26
|
dropdownStyle={{padding: "15px 20px", borderRadius: "20px", boxShadow: "0px 3.08px 16.47px 0px #00000040"}}
|
|
25
27
|
optionRender={(option) => (
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { mdiFileDownload, mdiMenu } from "@mdi/js";
|
|
2
2
|
import Icon from "@mdi/react";
|
|
3
|
-
import { Button, Drawer, Menu } from "antd";
|
|
3
|
+
import { Button, Drawer, Menu, notification } from "antd";
|
|
4
4
|
import React, { useState } from "react";
|
|
5
5
|
import type { MenuProps } from 'antd';
|
|
6
6
|
import { Link, useLocation, useMatch } from "react-router-dom";
|
|
7
|
+
import BrochueApi from "../../api-services/brochure-api.service";
|
|
7
8
|
|
|
8
9
|
type MenuItem = Required<MenuProps>['items'][number];
|
|
9
10
|
|
|
@@ -40,44 +41,91 @@ const items: MenuItem[] = [
|
|
|
40
41
|
},
|
|
41
42
|
]
|
|
42
43
|
|
|
43
|
-
const MainHeader = () => {
|
|
44
|
-
const [open, setOpen] = useState(false);
|
|
45
|
-
const location = useLocation();
|
|
46
|
-
const activeUrlKey = location.pathname.split("/").pop() || "app";
|
|
47
|
-
const [current, setCurrent] = useState(activeUrlKey);
|
|
48
44
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
45
|
+
function withLocation(Component) {
|
|
46
|
+
return props => <Component {...props} location={useLocation()} />;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class MainHeader extends React.Component <{location}> {
|
|
50
|
+
brochureApi = new BrochueApi;
|
|
51
|
+
|
|
52
|
+
state = {
|
|
53
|
+
open: false,
|
|
54
|
+
current: "",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
constructor(props:any){
|
|
58
|
+
super(props);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
componentDidMount() {
|
|
63
|
+
this.setLocation();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
downloadBrochure = () => {
|
|
68
|
+
this.brochureApi.getBrochure()
|
|
69
|
+
.then((brochureUrl:any) => {
|
|
70
|
+
// const blob = brochureUrl.blob();
|
|
71
|
+
// const blobURL = URL.createObjectURL(blob);
|
|
72
|
+
var a = document.createElement("a");
|
|
73
|
+
a.href = brochureUrl;
|
|
74
|
+
a.setAttribute('style', "display: none");
|
|
75
|
+
|
|
76
|
+
a.download = "Brochure";
|
|
77
|
+
document.body.appendChild(a);
|
|
78
|
+
a.click();
|
|
79
|
+
})
|
|
80
|
+
.catch(error => {
|
|
81
|
+
notification.error({ message: 'An error occured while getting brochure.'});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
}
|
|
53
85
|
|
|
54
|
-
const showDrawer = () => {
|
|
55
|
-
setOpen(true);
|
|
56
|
-
};
|
|
57
86
|
|
|
58
|
-
|
|
59
|
-
|
|
87
|
+
private setLocation(){
|
|
88
|
+
const location = this.props.location
|
|
89
|
+
const activeUrlKey = location.pathname.split("/").pop() || "app";
|
|
90
|
+
this.setState({current: activeUrlKey});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
onClick: MenuProps['onClick'] = (e) => {
|
|
95
|
+
this.setState({open: false, current: e.key})
|
|
60
96
|
};
|
|
61
|
-
|
|
62
|
-
return (
|
|
63
|
-
<div id="main-header">
|
|
64
|
-
<Menu mode="horizontal" items={items} onClick={onClick} selectedKeys={[current]} className="nav-menu"/>
|
|
65
97
|
|
|
66
|
-
|
|
98
|
+
showDrawer() {
|
|
99
|
+
this.setState({open: true});
|
|
100
|
+
};
|
|
67
101
|
|
|
68
|
-
|
|
69
|
-
|
|
102
|
+
onClose() {
|
|
103
|
+
this.setState({open: false});
|
|
104
|
+
};
|
|
70
105
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
106
|
+
render(){
|
|
107
|
+
const {open, current } = this.state;
|
|
108
|
+
return (
|
|
109
|
+
<div id="main-header">
|
|
110
|
+
<Menu mode="horizontal" items={items} onClick={this.onClick} selectedKeys={[current]} className="nav-menu"/>
|
|
111
|
+
|
|
112
|
+
<a href="/app"><img src="/iceholidays-assets/images/logo_mobile.png" className="logo logo_mobile"/></a>
|
|
113
|
+
|
|
114
|
+
<div id="nav-buttons">
|
|
115
|
+
<Button onClick={this.downloadBrochure} id="get-brochure" type="primary"><Icon path={mdiFileDownload} size="18px" /> get brochure</Button>
|
|
116
|
+
|
|
117
|
+
<Button id="toggle-menu" type="primary" onClick={()=>this.showDrawer()}>
|
|
118
|
+
<Icon path={mdiMenu} size="25px" />
|
|
119
|
+
</Button>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<Drawer title={null} onClose={()=>this.onClose()} open={open} id="nav-drawer">
|
|
123
|
+
<Menu items={items} onClick={this.onClick} selectedKeys={[current]} className="nav-menu_mobile"/>
|
|
124
|
+
</Drawer>
|
|
74
125
|
</div>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
</Drawer>
|
|
79
|
-
</div>
|
|
80
|
-
)
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
81
129
|
}
|
|
82
130
|
|
|
83
|
-
export default MainHeader;
|
|
131
|
+
export default withLocation(MainHeader);
|
|
@@ -26,12 +26,12 @@ const AboutUsPage = React.FC = () => (
|
|
|
26
26
|
<Col span={24}>
|
|
27
27
|
<img src="/iceholidays-assets/images/about_us2.png"/>
|
|
28
28
|
</Col>
|
|
29
|
-
<Col
|
|
29
|
+
<Col xs={24} sm={24} lg={12}>
|
|
30
30
|
<p>The Signature Tours was born from a passion for redefining travel. We believe that journeys should be more than just trips—they should be transformative experiences, filled with moments that leave an indelible mark on the soul. Catering to discerning travelers who seek more than the ordinary, The Signature Tours crafts bespoke journeys that combine sophistication, cultural immersion, and unparalleled quality. </p>
|
|
31
31
|
<p>Our story begins with a vision: to create journeys that linger in the heart long after the traveler returns home. Each itinerary we design reflects our dedication to perfection. From the charm of boutique accommodations nestled in picturesque landscapes to handpicked cultural experiences that unveil the soul of a destination, every detail is thoughtfully considered to ensure your journey is as seamless as it is extraordinary.</p>
|
|
32
32
|
<p>At The Signature Tours, we embrace the philosophy of the S-Tours experience—where every moment is a masterpiece. Imagine strolling through the cobblestone streets of a quaint village, savoring the aroma of freshly baked bread as locals welcome you with warm smiles. </p>
|
|
33
33
|
</Col>
|
|
34
|
-
<Col
|
|
34
|
+
<Col xs={24} sm={24} lg={12}>
|
|
35
35
|
<p>Picture yourself standing atop a majestic mountain at sunrise,the golden hues of the horizon reflecting the sense of awe within you. These are the kinds of moments we strive to create—authentic, meaningful, and unforgettable.</p>
|
|
36
36
|
<p>But our commitment goes beyond premium and comfort. It’s about forging connections—with places, cultures, and people. It’s about stepping into a story, whether it’s exploring ancient ruins with a seasoned archaeologist, learning the art of wine making from a passionate vintner, or sharing laughter with a local family over a home-cooked meal.</p>
|
|
37
37
|
<p>At The Signature Tours, every journey is an invitation to step out of the ordinary and into a world of wonder. We’re not just about travel; we’re about creating memories that stay with you forever. This is our promise, and this is what we call the S-Tours philosophy where we deliver S-Class Journeys, Signature Memories. Because every journey should be as unique as your signature.</p>
|
|
@@ -80,10 +80,10 @@ const AboutUsPage = React.FC = () => (
|
|
|
80
80
|
<p>We have acquired recognition and certificates such as:</p>
|
|
81
81
|
</div>
|
|
82
82
|
</Col>
|
|
83
|
-
<Col xs={24} sm={24} lg={8}>
|
|
83
|
+
<Col xs={24} sm={24} md={12} lg={8}>
|
|
84
84
|
<img src="/iceholidays-assets/images/certificate1.png"/>
|
|
85
85
|
</Col>
|
|
86
|
-
<Col xs={24} sm={24} lg={8}>
|
|
86
|
+
<Col xs={24} sm={24} md={12} lg={8}>
|
|
87
87
|
<img src="/iceholidays-assets/images/certificate2.png"/>
|
|
88
88
|
</Col>
|
|
89
89
|
</Row>
|
|
@@ -1,81 +1,97 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import Headline from "../components/shared/Headline";
|
|
3
|
-
import { Button, Card, Col, Row, Space } from "antd";
|
|
3
|
+
import { Button, Card, Col, notification, Row, Space } from "antd";
|
|
4
4
|
import FilterPills from "../widgets/FilterPills";
|
|
5
|
-
import
|
|
5
|
+
import PostsApi from "../../api-services/posts-api.service";
|
|
6
|
+
import { Blog } from "../../interfaces/blog.interface";
|
|
7
|
+
import Markdown from "react-markdown";
|
|
8
|
+
import rehypeRaw from "rehype-raw";
|
|
9
|
+
import remarkGfm from "remark-gfm";
|
|
6
10
|
const { Meta } = Card;
|
|
7
11
|
|
|
8
12
|
const bannerPath = '/iceholidays-assets/images/blog.png';
|
|
9
|
-
const
|
|
10
|
-
{ title:
|
|
11
|
-
{ title:
|
|
13
|
+
const _breadcrumbs = [
|
|
14
|
+
{ title: <a href="/app">Home</a> },
|
|
15
|
+
{ title: <a href="/app/blog">Blog</a> }
|
|
12
16
|
]
|
|
13
17
|
|
|
14
|
-
const types = [ "News", "Blogs" ];
|
|
15
|
-
const blogs = [
|
|
16
|
-
{
|
|
17
|
-
id: 1,
|
|
18
|
-
cover: "/iceholidays-assets/images/blog1.png",
|
|
19
|
-
title: "旅游的意义:探索世界与内心的旅程",
|
|
20
|
-
info: "未分类 / 发表评论 / 2024年11月22日",
|
|
21
|
-
summary: "旅游不仅拓展视野,也带来人生的启示。它教会我们谦逊、适应变化、享受过程,激发内心力量,感恩遇见,并帮助我们找回初心。"
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
id: 2,
|
|
25
|
-
cover: "/iceholidays-assets/images/blog1.png",
|
|
26
|
-
title: "旅游的意义:探索世界与内心的旅程",
|
|
27
|
-
info: "未分类 / 发表评论 / 2024年11月22日",
|
|
28
|
-
summary: "旅游不仅拓展视野,也带来人生的启示。它教会我们谦逊、适应变化、享受过程,激发内心力量,感恩遇见,并帮助我们找回初心。"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
id: 3,
|
|
32
|
-
cover: "/iceholidays-assets/images/blog1.png",
|
|
33
|
-
title: "旅游的意义:探索世界与内心的旅程",
|
|
34
|
-
info: "未分类 / 发表评论 / 2024年11月22日",
|
|
35
|
-
summary: "旅游不仅拓展视野,也带来人生的启示。它教会我们谦逊、适应变化、享受过程,激发内心力量,感恩遇见,并帮助我们找回初心。"
|
|
36
|
-
},
|
|
37
|
-
]
|
|
18
|
+
const types = [ {type: "News", label: "News"},{type: "Blogs", label:"Blogs"} ];
|
|
38
19
|
|
|
39
|
-
const setFilter = (selectedFilter) => {
|
|
40
|
-
console.log("set filter", selectedFilter)
|
|
41
|
-
}
|
|
42
20
|
|
|
21
|
+
export default class BlogPage extends React.Component {
|
|
22
|
+
postsApi = new PostsApi;
|
|
43
23
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
24
|
+
state = {
|
|
25
|
+
blogs: [],
|
|
26
|
+
breadcrumbs: _breadcrumbs,
|
|
27
|
+
searchParamsObj: {type: "", year: "", month: ""},
|
|
28
|
+
}
|
|
47
29
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
30
|
+
componentDidMount() {
|
|
31
|
+
this.postsApi.getBlogs()
|
|
32
|
+
.then(blogsData => {
|
|
33
|
+
this.setState({blogs: blogsData})
|
|
34
|
+
})
|
|
35
|
+
.catch(error => {
|
|
36
|
+
notification.error({ message: 'An error occured while loading blogs.'});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
52
39
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
40
|
+
setFilter = (selectedFilter) => {
|
|
41
|
+
const {breadcrumbs} = this.state;
|
|
42
|
+
breadcrumbs[2] = {title: this.searchParamsToText()};
|
|
43
|
+
|
|
44
|
+
const allHasValues = Object.entries(selectedFilter).every(o => o[1] != "" && o[1] != null);
|
|
45
|
+
if(allHasValues){
|
|
46
|
+
breadcrumbs[1] = {title: <span>Search results</span>};
|
|
47
|
+
}
|
|
48
|
+
this.setState({searchParamsObj: selectedFilter, breadcrumbs})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
searchParamsToText() {
|
|
53
|
+
var {type, year, month} = this.state.searchParamsObj;
|
|
54
|
+
const monthYear = (month || year) && `${month} ${year}`;
|
|
55
|
+
const text = [type, monthYear].filter(val => val).join(", ");
|
|
56
|
+
return <span>{ text } </span>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
render(){
|
|
60
|
+
const {blogs, breadcrumbs, searchParamsObj} = this.state;
|
|
61
|
+
return (
|
|
62
|
+
<div id="blog-page">
|
|
63
|
+
<Headline bannerImage={bannerPath} breadcrumbs={breadcrumbs} title="Blog"/>
|
|
64
|
+
|
|
65
|
+
<div id="blog-page_body">
|
|
66
|
+
<Space size={12} direction="vertical">
|
|
67
|
+
<FilterPills items={types} bindValue="type" allOption={true} initialValue={searchParamsObj} selectFilter={(selected)=>this.setFilter(selected)}></FilterPills>
|
|
68
|
+
</Space>
|
|
69
|
+
|
|
70
|
+
<div id="blogs">
|
|
71
|
+
<Row wrap gutter={20}>
|
|
72
|
+
{
|
|
73
|
+
blogs.map((blog:Blog) => (
|
|
74
|
+
<Col key={blog.id} span={8}>
|
|
75
|
+
<Card cover={<img alt={blog.title} src={blog.thumbnail} />}>
|
|
76
|
+
<Meta title={blog.title} description={
|
|
77
|
+
<>
|
|
78
|
+
{/* <span>{blog.info}</span> */}
|
|
79
|
+
<div className="preview-content">
|
|
80
|
+
<Markdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]}>{blog.content}</Markdown>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<Button className="view-blog" href={`/app/blog/${blog.id}`} type="link" color="primary" variant="outlined" block>阅读更多</Button>
|
|
84
|
+
</>
|
|
85
|
+
} />
|
|
86
|
+
</Card>
|
|
87
|
+
</Col>
|
|
88
|
+
))
|
|
89
|
+
}
|
|
90
|
+
</Row>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
76
93
|
</div>
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
);
|
|
94
|
+
)
|
|
95
|
+
}
|
|
80
96
|
|
|
81
|
-
|
|
97
|
+
}
|
|
@@ -1,43 +1,58 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import Headline from "../components/shared/Headline";
|
|
3
|
+
import PostsApi from "../../api-services/posts-api.service";
|
|
4
|
+
import { useParams } from "react-router-dom";
|
|
5
|
+
import { notification } from "antd";
|
|
6
|
+
import Markdown from "react-markdown";
|
|
7
|
+
import rehypeRaw from "rehype-raw";
|
|
8
|
+
import remarkGfm from "remark-gfm";
|
|
3
9
|
|
|
4
10
|
const bannerPath = '/iceholidays-assets/images/blog.png';
|
|
5
|
-
const
|
|
11
|
+
const _breadcrumbs = [
|
|
6
12
|
{ title: 'Home' },
|
|
7
13
|
{ title: 'Blog' },
|
|
8
|
-
{ title: '从斯里兰卡到马尔代夫' },
|
|
9
14
|
]
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
16
|
+
function withParams(Component) {
|
|
17
|
+
return props => <Component {...props} params={useParams()} />;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class BlogShowPage extends React.Component <{params;}> {
|
|
21
|
+
postsApi = new PostsApi;
|
|
22
|
+
|
|
23
|
+
state = {
|
|
24
|
+
breadcrumbs: _breadcrumbs,
|
|
25
|
+
blog: {title: "", thumbnail: "", content: ""},
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
componentDidMount() {
|
|
29
|
+
this.postsApi.getBlog(this.props.params.id)
|
|
30
|
+
.then(blogData => {
|
|
31
|
+
var breadcrumbs = this.state.breadcrumbs;
|
|
32
|
+
breadcrumbs.push({title: blogData.title});
|
|
33
|
+
this.setState({blog: blogData, breadcrumbs})
|
|
34
|
+
})
|
|
35
|
+
.catch(error => {
|
|
36
|
+
notification.error({ message: 'An error occured while loading blog.'});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
render(){
|
|
42
|
+
const {blog} = this.state;
|
|
43
|
+
return (
|
|
44
|
+
<div id="blog-show-page">
|
|
45
|
+
<Headline bannerImage={bannerPath} breadcrumbs={this.state.breadcrumbs} title="Blog"/>
|
|
46
|
+
|
|
47
|
+
<div id="blog-show-page_body">
|
|
48
|
+
<h1>{blog.title}</h1>
|
|
49
|
+
<img src={blog.thumbnail}/>
|
|
50
|
+
<Markdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]}>{blog.content}</Markdown>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
export default withParams(BlogShowPage);
|