Markdownエディタを作成します.JTTUBアクションによる配備をもつJSとタイプスクリプト


私はfreecodecampをしていたとき、私はプロジェクトのいずれかでMarkdownエディタを作成しようとしていた覚えている.それで、今回はMarkdown Editorと一緒に行き、反応と組み合わせました.JSとタイプスクリプト.

何を学ぶ

  • 反応の設定JSプロジェクト
  • HTMLにコンパイルすることによって、Markdownエディタを作成すること
  • アプリケーションのためのテーマを作成するために反応フックを使用する
  • Githubアクションによる連続展開
  • 私は怠惰な人です、あなたの大部分もそうであると思います.それで、あなたが直接彼らを見たいならば、コードとデモリンクはここにあります.

    プロジェクトソースコード:


    アシュワーム / 対応するスクリプトの編集


    反応の使用によるMarkdownエディタ。JTTUBアクションワークフローを使用して連続展開と組み合わせるJSとTypesScript


    プロジェクトデモ:Ashwamegh /反応TypeScriptのマークダウンエディタ


    プロジェクトの設定から始めましょう

    1 .プロジェクトを設定します。JSとタイプスクリプト


    私たちはすべてのタイプスクリプトの機能を知って、どのようにあなたの愚かなミスの日を保存することができます.そして、反応と結合されるならば、彼らはどんなアプリケーションにでも力を与えるすばらしい組合せになります.
    私は使用されますcreate-react-app 以来、それはボックスから入力スクリプトをサポートします.ルートディレクトリに移動し、プロジェクトを作成し、このコマンドを実行します.
    npx create-react-app markdown-editor --template typescript
    
    
    この--template typescript フラグはあなたのためのすべてのハードワークを行い、反応を設定します.JSプロジェクト.
    後で、ブートストラップされたコードの一部を削除してアプリケーションを作成する必要があります.
    参考のために、この初期のコミットをチェックして、何が削除されたかを確認できます.https://github.com/ashwamegh/react-typescript-markdown-editor/commit/7cc379ec0d01f3f1a07396ff2ac6c170785df57bあなたが最初の手順を完了した後、最終的に我々のマルクダウンエディタを作成するに移動します.

    2 . Markdownエディタの作成


    コードに飛び込む前に、プロジェクトのフォルダ構造を見てみましょう.
    ├── README.md
    ├── package.json
    ├── public
    |  ├── favicon.ico
    |  ├── index.html
    |  ├── logo192.png
    |  ├── logo512.png
    |  ├── manifest.json
    |  └── robots.txt
    ├── src
    |  ├── App.test.tsx
    |  ├── App.tsx
    |  ├── components
    |  |  ├── Editor.tsx
    |  |  ├── Footer.tsx
    |  |  ├── Header.tsx
    |  |  ├── Main.tsx
    |  |  ├── Preview.tsx
    |  |  └── shared
    |  |     └── index.tsx
    |  ├── index.css
    |  ├── index.tsx
    |  ├── react-app-env.d.ts
    |  ├── serviceWorker.ts
    |  ├── setupTests.ts
    |  └── userDarkMode.js
    ├── tsconfig.json
    └── yarn.lock
    
    私は使用されますemotion コンポーネントとスタイルの作成react-icons プロジェクトで使用するアイコン.だからインストールする必要があるでしょうemotion and react-icons このコマンドを実行します.
    npm i -S @emotion/core @emotion/styled react-icons
    
    または使用している場合yarn 私のように
    yarn add @emotion/core @emotion/styled react-icons
    
    まず最初に、我々はshared コンポーネントフォルダを作成するコンポーネントを再利用されます.
    
    /* src/components/shared/index.tsx */
    
    import React from 'react'
    import styled from '@emotion/styled'
    
    export const ColumnFlex = styled.div`
      display: flex;
      flex-direction: column;
    `
    export const RowFlex = styled.div`
      display: flex;
      flex-direction: row;
    `
    
    

    In this file, we have declared two styled components for flex-column and flex-row styled divs which we'll be using later.
    To know more about styled-components with emotion library, head on to this link.


    3反応フックを使用してカスタムテーマフックを作成する


    我々は、我々は光から暗い色まで私たちのテーマを切り替えることができます使用して、基本的なテーマ機能を実装するために私たちのカスタムフックを作成するために反応フックを使用します.
    /* useDarMode.js */
    
    import { useEffect, useState } from 'react'
    
    export default () => {
      const [theme, setTheme] = useState('light')
    
      const toggleTheme = () => {
        if (theme === 'dark') {
          setTheme('light')
        } else {
          setTheme('dark')
        }
      }
    
      useEffect(() => {
        const localTheme = localStorage.getItem('theme')
        if (localTheme) {
          setTheme(localTheme)
        }
      }, [])
    
      return {
        theme,
        toggleTheme,
      }
    }
    

    In our hooks file, we are setting the initial state of the theme to be light using useState hook. And using useEffect to check whether any theme item exists in our browser's local storage, and if there is one, pick the theme from there and set it for our application.


    以来、私たちは私たちの共有コンポーネントとカスタムをテーマに、私たちのアプリのコンポーネントに飛び込みましょうフックの反応を定義している.
    だから、私は5つのコンポーネントに我々のアプリの構造を分割している:ヘッダー、メイン(エディタ&プレビューコンポーネントとアプリケーションのメインセクションが含まれています)とフッターコンポーネント.
  • ヘッダー/通常のヘッダーコードとトグルテーマへのスイッチを含みます
  • エディタおよびプレビューコンポーネントのメインコンテナ
    エディタのためのコード
    IIプレビュー//マークダウンコードをHTMLにプレビューするコードが含まれています
  • 通常のフッターコード
  • /* src/components/Header.tsx */
    
    import React from 'react'
    import { FiSun } from 'react-icons/fi'
    import { FaMoon } from 'react-icons/fa'
    
    // this comment tells babel to convert jsx to calls to a function called jsx instead of React.createElement
    /** @jsx jsx */
    import { css, jsx } from '@emotion/core'
    
    // Prop check in typescript
    interface Props {
      toggleTheme: () => void,
      theme: string
    }
    
    const Header: React.FC<Props> = ({ theme, toggleTheme }) => {
    
      return (
        <header
          css={theme === 'dark' ?
          css`
            display: flex;
            flex-direction: row;
            justify-content: space-between;
            background-color: #f89541;
            padding: 24px 32px;
            font-size: 16px;
          `:css`
            display: flex;
            flex-direction: row;
            justify-content: space-between;
            background-color: #f8f541;
            padding: 24px 32px;
            box-shadow: 0px -2px 8px #000;
            font-size: 16px;
        `}>
          <div className="header-title">
            Markdown Editor
          </div>
          <div css={
            css`
              cursor: pointer;
            `}
            onClick={toggleTheme}
          >
           {
             theme === 'dark'?
             <FaMoon />:
             <FiSun />
           }
          </div>
        </header>
      )
    }
    
    export default Header;
    

    In this component, we are using TypeScript for prop checks and you may wonder, why we're mentioning React.FC here. Its just that, by typing our component as an FC (FunctionComponent), the React TypeScripts types allow us to handle children and defaultProps correctly.


    我々のコンポーネントを使用してスタイリングのためにcss 文字列形式のプロップemotion ライブラリについては、ドキュメントに従うことにより、これについての詳細を学ぶことができますhere
    ヘッダーコンポーネントを作成した後、フッターコンポーネントを作成し、メインコンポーネントに移動します.
    フッターコンポーネントのコードを見ましょう
    import React from 'react'
    
    // this comment tells babel to convert jsx to calls to a function called jsx instead of React.createElement
    /** @jsx jsx */
    import { css, jsx } from '@emotion/core'
    
    const Footer: React.FC = () => {
    
      return (
        <footer>
          <div 
            className="footer-description"
            css={
                css`
                    padding: 16px 0px;
                    overflow: hidden;
                    position: absolute;
                    width: 100%;
                    text-align: center;
                    bottom: 0px;
                    color: #f89541;
                    background: #000;
                `
            }>
           <span>{`</>`}</span><span> with <a href="https://reactjs.org" target="_blank">React.js</a> &amp; <a href="https://www.typescriptlang.org/" target="_blank">TypeScript</a></span>
          </div>
        </footer>
      )
    }
    
    export default Footer;
    
    
    Footerコンポーネントは、通常のクレジットをレンダリングする単純なコードが含まれます.
    /* src/components/Main.tsx */
    
    import React, { useState } from 'react'
    
    // this comment tells babel to convert jsx to calls to a function called jsx instead of React.createElement
    /** @jsx jsx */
    import { css, jsx } from '@emotion/core'
    import { RowFlex } from './shared'
    import Editor from './Editor';
    import Preview from './Preview';
    
    interface Props {
      theme: string
    }
    
    const Main: React.FC<Props> =  ({ theme }) => {
      const [markdownContent, setMarkdownContent] = useState<string>(`
    # H1
    ## H2
    ### H3
    #### H4
    ##### H5
    
    __bold__
    **bold**
    _italic_
    `);
      return (
        <RowFlex
          css={css`
            padding: 32px;
            padding-top: 0px;
            height: calc(100vh - 170px);
            `}>
          <Editor theme={theme} markdownContent={markdownContent} setMarkdownContent={setMarkdownContent}/>
          <Preview theme={theme} markdownContent={markdownContent}/>
        </RowFlex>
      )
    }
    
    export default Main;
    
    
    以来、コードのいくつかは、あなたが今あなた自身を理解できる前のコンポーネントからあなたに精通しているように見えます.それ以外は、我々は使用しているuseState フックのマークダウンコンテンツとハンドラを保持する状態を作成するsetMarkdownContent コードで.

    We need to pass these down to our Editor and Preview components, so that, they can provide the user the way to edit and preview their markdown content. We have also set an initial state for content with some basic markdown text.


    エディタコンポーネントのコードを参照してください.
    /* src/components/Editor.tsx */
    
    import React, { ChangeEvent } from 'react'
    import PropTypes from 'prop-types';
    
    // this comment tells babel to convert jsx to calls to a function called jsx instead of React.createElement
    /** @jsx jsx */
    import { css, jsx } from '@emotion/core'
    import { ColumnFlex } from './shared'
    
    interface Props {
      markdownContent: string;
      setMarkdownContent: (value: string) => void,
      theme: string
    }
    
    const Editor: React.FC<Props> = ({ markdownContent, setMarkdownContent, theme }) => {
        return (
            <ColumnFlex
            id="editor"
            css={css`
                flex: 1;
                padding: 16px;
              `}>
            <h2>
            Editor
            </h2>
            <textarea
              onChange={(e: ChangeEvent<HTMLTextAreaElement>) => setMarkdownContent(e.target.value)}
              css={theme === 'dark'?
              css`
                height: 100%;
                border-radius: 4px;
                border: none;
                box-shadow: 0 -2px 10px rgba(0, 0, 0, 1);
                background: #000;
                color: #fff;
                font-size: 100%;
                line-height: inherit;
                padding: 8px 16px;
                resize: none;
                overflow: auto;
                &:focus {
                  outline: none;
                }
              `
              : css`
                height: 100%;
                border-radius: 4px;
                border: none;
                box-shadow: 2px 2px 10px #999;
                font-size: 100%;
                line-height: inherit;
                padding: 8px 16px;
                resize: none;
                overflow: auto;
                &:focus {
                  outline: none;
                }
              `}
              rows={9}
              value={markdownContent}
              />
          </ColumnFlex>
        )
    }
    
    Editor.propTypes = {
      markdownContent: PropTypes.string.isRequired,
      setMarkdownContent: PropTypes.func.isRequired,
    }
    
    export default Editor;
    

    This is a straight forward component which uses <textarea/> to provide the user a way to enter their inputs, which have to be further compiled down to render it as HTML content in the Preview component.


    ここで、プレビューコンポーネント以外のほとんどのコンポーネントを作成しました.
    ユーザのマークダウンコンテンツを簡単なHTMLにコンパイルするために何かを必要とするでしょう.そして、私たちにはすべてのコンパイラコードを書きたくありません.
    このアプリケーションでは、我々は使用されますmarked ライブラリをHTMLにマークダウンコンテンツをコンパイルする.したがって、このコマンドを実行することで、インストールする必要があります.
    npm i -S marked
    
    または糸で
    yarn add marked
    

    If you want to know more about this library, you can see it here


    プレビューコンポーネントのコードを見ましょう
    /* src/components/Preview.tsx */
    
    import React from 'react'
    import PropTypes from 'prop-types'
    import marked from 'marked'
    
    // this comment tells babel to convert jsx to calls to a function called jsx instead of React.createElement
    /** @jsx jsx */
    import { css, jsx } from '@emotion/core'
    import { ColumnFlex } from './shared'
    
    interface Props {
        markdownContent: string,
        theme: string
    }
    
    const Preview: React.FC<Props> = ({ markdownContent, theme }) => {
        const mardownFormattedContent = ( marked(markdownContent));
    
        return (
            <ColumnFlex
                id="preview"
                css={css`
                flex: 1;
                padding: 16px;
                `}
            >
                <h2>Preview</h2>
                <div
                    css={theme === 'dark'
                    ? css`
                    height: 100%;
                    border-radius: 4px;
                    border: none;
                    box-shadow: 0 -2px 10px rgba(0, 0, 0, 1);
                    font-size: 100%;
                    line-height: inherit;
                    overflow: auto;
                    background: #000;
                    padding: 8px 16px;
                    color: #fff;
                    `
                    : css`
                    height: 100%;
                    border-radius: 4px;
                    border: none;
                    box-shadow: 2px 2px 10px #999;
                    font-size: 100%;
                    line-height: inherit;
                    overflow: auto;
                    background: #fff;
                    padding: 8px 16px;
                    color: #000;
                `}
                dangerouslySetInnerHTML={{__html: mardownFormattedContent}}
                >
                </div>
            </ColumnFlex>
        )
    }
    
    Preview.propTypes = {
        markdownContent: PropTypes.string.isRequired
      }
    
    export default Preview;
    

    In this component, we are compiling the markdown content and storing it in mardownFormattedContent variable. And to show a preview of the content in HTML, we will have to use dangerouslySetInnerHTML prop to display the HTML content directly into our DOM, which we are doing by adding this dangerouslySetInnerHTML={{__html: mardownFormattedContent}} prop for the div element.


    最後に、私たちのMarkdown Editorアプリケーションを作成する必要があるすべてのコンポーネントで準備ができています.私たちのすべてを持っていきましょうApp.tsx ファイル.
    /* src/App.tsx */
    
    import React from 'react'
    import { css, jsx } from '@emotion/core'
    
    // Components
    import Header from './components/Header'
    import Main from './components/Main'
    import Footer from './components/Footer';
    import useDarkMode from './userDarkMode';
    
    function App() {
      const { theme, toggleTheme } = useDarkMode();
      const themeStyles = theme === 'light'? {
        backgroundColor: '#eee',
        color: '#000'
      }: {
        backgroundColor: '#171616',
        color: '#fff'
      }
      return (
        <div 
          className="App"
          style={themeStyles}
          >
          <Header theme={theme} toggleTheme={toggleTheme}/>
          <Main theme={theme}/>
          <Footer />
        </div>
      );
    }
    
    export default App;
    
    
    我々のアプリのコンポーネントでは、我々は、子コンポーネントをインポートし、テーマの小道具を渡す.
    さて、上記のすべての手順に従っているならば、実行中のMarkdown Editorアプリケーションを持っているでしょう、私が使用したスタイルのために、あなたは私が述べたリンクを使用して私のソースコードを見ることができます.

    Now, its time to create Github actions for our project to create continuous deployment workflow on every push to master.


    4 githubアクションを通して連続配備を準備すること


    我々は、Githubアクションのワークフローを使用してビルドし、すべてのプッシュをマスターにWebアプリケーションを展開します.

    Since this is not a enterprise application that holds the branches for production and development, I will setup my workflow for master branch, but if in any time in future, you require to setup the Github action workflow for your enterprise application, Just be careful with the branches.


    そのためにいくつかの手順に従います.
  • プロジェクトのルートディレクトリにフォルダを作成する.github/workflows/ , これはすべてのワークフロー設定を保持します.
  • 私たちは JamesIves/github-pages-deploy-action アプリケーションを配備するアクション.
  • 次に、我々は我々をつくります.yml ここでは、Githubページへのアプリケーションのビルドと配備の責任があります.名前を挙げましょうbuild-and-deploy-to-gh-pages.yml
  • 何がこの中に入るか見ましょうbuild-and-deploy-to-gh-pages.yml
    # build-and-deploy-to-gh-pages.yml
    
    name: Build & deploy to GitHub Pages
    on:
      push:
        branches:
          - master
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout
            uses: actions/checkout@v1
          - name: Set up Node
            uses: actions/setup-node@v1
            with:
              node-version: 10.x 
          - name: Set email
            run: git config --global user.email "${{ secrets.adminemail }}"
          - name: Set username
            run: git config --global user.name "${{ secrets.adminname }}"
          - name: npm install command
            run: npm install
          - name: Run build command
            run: npm run build
          - name: Deploy
            uses: JamesIves/github-pages-deploy-action@releases/v3
            with:
              GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
              BASE_BRANCH: master
              BRANCH: gh-pages # The branch the action should deploy to.
              FOLDER: build # The folder the action should deploy.
    
    このワークフローは、毎回実行され、我々はマスターに何かをプッシュしてgh-pages 枝.
    ワークフローファイルを破壊しましょう
    name: Build & deploy to GitHub Pages
    on:
      push:
        branches:
          - master
    
    これは、ワークフローの名前とトリガーを定義し、その中のジョブを実行します.ここでは、トリガを設定する任意のを聞いているPush イベントmaster 枝.
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout
            uses: actions/checkout@v1
          - name: Set up Node
            uses: actions/setup-node@v1
            with:
              node-version: 10.x 
          - name: Set email
            run: git config --global user.email "${{ secrets.adminemail }}"
          - name: Set username
            run: git config --global user.name "${{ secrets.adminname }}"
          - name: npm install command
            run: npm install
          - name: Run build command
            run: npm run build
          - name: Deploy
            uses: JamesIves/github-pages-deploy-action@releases/v3
            with:
              GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
              BASE_BRANCH: master
              BRANCH: gh-pages # The branch the action should deploy to.
              FOLDER: build # The folder the action should deploy.
    
    これは、我々のワークフローで最も重要な部分ですjobs される.設定の行のいくつかは自明ですruns-on: ubuntu-latest これはシステムを定義します.
    - name: Checkout
            uses: actions/checkout@v1
    
    これはREPOをチェックするためのアクションで、後のジョブではノードをインストールしてGitプロファイル設定を設定して開発環境を設定しています.その後、我々は実行しているnpm install すべての依存関係を引き出し、最終的に実行するbuild コマンド.
    - name: Deploy
            uses: JamesIves/github-pages-deploy-action@releases/v3
            with:
              GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
              BASE_BRANCH: master
              BRANCH: gh-pages # The branch the action should deploy to.
              FOLDER: build # The folder the action should deploy.
    

    After the build command has been completed, we are using JamesIves/github-pages-deploy-action@releases/v3 action to deploy our build folder to gh-pages.


    いつでも、あなたのマスターブランチに何かをプッシュしますgh-pages 枝.

    さて、展開が完了したら、すべてのあなたのアプリケーションをgithubリンクを実行しているhttps://yourusername.github.io/markdown-editor/ .

    Don't forget to add "homepage" : "https://yourusername.github.io/markdown-editor/" in package.json file, otherwise serving of static contents may cause problem.


    あなたが私の記事が好きならば、あなたは私の毎日の紙のためにさえずりの上で私に続くことができますThe JavaSc®ipt Showcase , また、あなたはGithubの上に私の個人的なプロジェクトに従うことができます.コメントを投稿してください.ありがとう
    液体誤差:内部

    アシュワーム / 対応するスクリプトの編集


    反応の使用によるMarkdownエディタ。JTTUBアクションワークフローを使用して連続展開と組み合わせるJSとTypesScript