iThome
鐵人賽
30天
這次markdown editor決定採用@uiw/react-md-editor,不過畢竟我也沒用過,就當作試用來用看看囉!
先來安裝套件:
npm i @uiw/react-md-editor
因為這套件裡面就有內建Markdown的渲染了,所以來替代昨天用的ReactMarkdown
吧~
修改MarkView.jsx
並增加onDoubleClick事件來幫助觸發編輯:
import React from 'react'
import { Button, Box } from '@mui/material'
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import MDEditor from '@uiw/react-md-editor'
export default function MarkView(props) {
const { sec, content, onDoubleClick } = props
return (
<Box sx={{ p: 1 }}>
<Button size="small" variant="outlined">{parseInt(sec / 60)}:{(((sec - parseInt(sec / 60) * 60) / 100).toFixed(2)).split('.')[1]}</Button>
<Box
sx={{ border: "1px solid #000", p: 1, margin: "5px 0", borderRadius: "10px", backgroundColor: "#fff" }}
component="div"
>
<article onDoubleClick={e => onDoubleClick(e)}>
<MDEditor.Markdown source={content} linkTarget="_blank" style={{ padding: 10 }} />
</article>
</Box>
</Box>
)
}
目前畫面:
測試的onDoubleClick也是正常的:
那再來就是雙擊後觸發編輯畫面了!我的打算是把整個右半邊的標記部分全部都變為編輯器,這樣範圍比較大編輯起來也比較舒服~
另外我把右邊的標記畫面也分開成另一個component,放在/src/components/Main/MarkPage.jsx
之中,所以目前WatchPage
長這個樣子:
export default function WatchPage(props) {
const { } = props
const [player, setPlayer] = useState(null)
return (
<Box sx={{ display: "flex", height: '100%', overflow: "auto" }} >
<Box sx={{ width: "70%" }} className="watch_wrapper">
<div className='video_wrapper'>
<div className='video_container'>
<div id="player" width="100%"></div>
</div>
</div>
<YouTubeIframe
v={"Ga22mpTDS6A"}
t={0}
playerid="player"
player={player}
setPlayer={pl => setPlayer(pl)}
/>
</Box>
<Box sx={{ width: "30%", position: "relative" }} className="mark_container">
<MarkPage />
</Box>
</Box>
)
}
製作編輯畫面一樣使用套件即可,並且設定按下esc
就離開編輯畫面。
/src/components/Main/MarkPage.jsx
:
import React, { useState, useEffect, useRef } from 'react'
import MarkView from '../elements/MarkView'
import MDEditor from '@uiw/react-md-editor'
export default function MarkPage(props) {
const [isEdit, setEdit] = useState(false)
const [mdInfo, setMdInfo] = useState({ content: null, id: null, sec: null })
const content = ``
// 當按下esc離開編輯器
const handleKeydown = (e) => {
if (e.keyCode == 27) {
setEdit(false)
}
}
useEventListener('keydown', handleKeydown)
return (
<>
{!!isEdit &&
<MDEditor
value={mdInfo.content}
onChange={value => setMdInfo({ ...mdInfo, content: value })}
style={{ position: "absolute", zIndex: "1" }}
height="100%"
width="100%"
className='md_editor'
/>
}
<MarkView
sec={33}
content={content}
onDoubleClick={e => setEdit(!isEdit)}
/>
</>
)
}
function useEventListener(eventName, handler, element = window) {
const savedHandler = useRef();
useEffect(() => {
savedHandler.current = handler;
}, [handler]);
useEffect(() => {
const isSupported = element && element.addEventListener;
if (!isSupported) return;
const eventListener = (event) => savedHandler.current(event);
element.addEventListener(eventName, eventListener);
return () => {
element.removeEventListener(eventName, eventListener);
};
}, [eventName, element]);
}
這裡會用isEdit
來控制編輯器的出現,並且在按下esc (keyCode: 27) 鍵來把isEdit
變為false。然後按下編輯時,會把要編輯的原始內容跟編號放到mdInfo
之中,編輯的畫面就會從中取得資料去做編輯,並由onChange
即時更新mdInfo
內的content
。
底下的useEventListener
就看看就好,因為時間不多所以不多做深入的介紹了,反正由於hook的關係,使用原本的lisener方式會導致一些小問題,所以才要把listener另外獨立出來變成另一個component。
點兩下之後的編輯畫面
今天完工後就只剩下API的製作與介接和Redux Saga的介紹與應用啦!API應該會在明天先把基本的功能都實作出來,但是為了簡單就不用使用到資料庫了,先單純以JSON檔案來控制標記。
附上專案:2022-iThomeIronman
對資安或Mapbox有興趣的話也可以觀看我們團隊的鐵人發文喔~