diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 2ad0a91..1da2244 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -9,4 +9,8 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username -custom: ["https://www.paypal.me/yang991178", "https://hyliu.me/fluent-reader/imgs/alipay.jpg"] +custom: + [ + "https://www.paypal.me/yang991178", + "https://hyliu.me/fluent-reader/imgs/alipay.jpg", + ] diff --git a/.github/workflows/release-linux.yml b/.github/workflows/release-linux.yml index 2e0426d..fd9ac50 100644 --- a/.github/workflows/release-linux.yml +++ b/.github/workflows/release-linux.yml @@ -1,39 +1,39 @@ name: CI/CD Release Linux on: - release: - types: - - published + release: + types: + - published jobs: - release-linux: - runs-on: ubuntu-latest + release-linux: + runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 + steps: + - uses: actions/checkout@v2 - - name: Build and package the app - run: | - sudo npm install --unsafe-perm=true --allow-root - npm run build - sudo npm run package-linux + - name: Build and package the app + run: | + sudo npm install --unsafe-perm=true --allow-root + npm run build + sudo npm run package-linux - - name: Get app version - id: package-version - uses: martinbeentjes/npm-get-version-action@master + - name: Get app version + id: package-version + uses: martinbeentjes/npm-get-version-action@master - - name: Get release - id: get_release - uses: bruceadams/get-release@v1.2.0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Get release + id: get_release + uses: bruceadams/get-release@v1.2.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Upload AppImage to release assets - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.get_release.outputs.upload_url }} - asset_path: ./bin/linux/x64/Fluent Reader-${{ steps.package-version.outputs.current-version }}.AppImage - asset_name: Fluent.Reader.${{ steps.package-version.outputs.current-version }}.AppImage - asset_content_type: application/octet-stream + - name: Upload AppImage to release assets + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.get_release.outputs.upload_url }} + asset_path: ./bin/linux/x64/Fluent Reader-${{ steps.package-version.outputs.current-version }}.AppImage + asset_name: Fluent.Reader.${{ steps.package-version.outputs.current-version }}.AppImage + asset_content_type: application/octet-stream diff --git a/.github/workflows/release-main.yml b/.github/workflows/release-main.yml index 90e8a1a..1a1e7aa 100644 --- a/.github/workflows/release-main.yml +++ b/.github/workflows/release-main.yml @@ -1,77 +1,77 @@ name: CI/CD Release on: - push: - tags: - - 'v*' - + push: + tags: + - "v*" + jobs: - release: - runs-on: windows-latest + release: + runs-on: windows-latest - steps: - - uses: actions/checkout@v2 + steps: + - uses: actions/checkout@v2 - - name: Build and package the app - run: | - npm install - npm run build - npm run package-win-ci + - name: Build and package the app + run: | + npm install + npm run build + npm run package-win-ci - - name: Get app version - id: package-version - run: | - PACKAGE_VERSION=$(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[",]//g' | tr -d '[[:space:]]') - echo ::set-output name=current-version::$PACKAGE_VERSION - shell: bash + - name: Get app version + id: package-version + run: | + PACKAGE_VERSION=$(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[",]//g' | tr -d '[[:space:]]') + echo ::set-output name=current-version::$PACKAGE_VERSION + shell: bash - - name: Create release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: Fluent Reader v${{ steps.package-version.outputs.current-version }} - draft: true - prerelease: false - - - name: Upload x64 exe to release assets - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./bin/win32/x64/Fluent Reader Setup ${{ steps.package-version.outputs.current-version }}.exe - asset_name: Fluent.Reader.Setup.${{ steps.package-version.outputs.current-version }}.x64.exe - asset_content_type: application/vnd.microsoft.portable-executable + - name: Create release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Fluent Reader v${{ steps.package-version.outputs.current-version }} + draft: true + prerelease: false - - name: Upload x86 exe to release assets - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./bin/win32/ia32/Fluent Reader Setup ${{ steps.package-version.outputs.current-version }}.exe - asset_name: Fluent.Reader.Setup.${{ steps.package-version.outputs.current-version }}.x86.exe - asset_content_type: application/vnd.microsoft.portable-executable + - name: Upload x64 exe to release assets + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./bin/win32/x64/Fluent Reader Setup ${{ steps.package-version.outputs.current-version }}.exe + asset_name: Fluent.Reader.Setup.${{ steps.package-version.outputs.current-version }}.x64.exe + asset_content_type: application/vnd.microsoft.portable-executable - - name: Upload x64 zip to release assets - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./bin/win32/x64/Fluent Reader-${{ steps.package-version.outputs.current-version }}-win.zip - asset_name: Fluent.Reader.Unpacked.${{ steps.package-version.outputs.current-version }}.x64.zip - asset_content_type: application/zip + - name: Upload x86 exe to release assets + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./bin/win32/ia32/Fluent Reader Setup ${{ steps.package-version.outputs.current-version }}.exe + asset_name: Fluent.Reader.Setup.${{ steps.package-version.outputs.current-version }}.x86.exe + asset_content_type: application/vnd.microsoft.portable-executable - - name: Upload x86 zip to release assets - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./bin/win32/ia32/Fluent Reader-${{ steps.package-version.outputs.current-version }}-ia32-win.zip - asset_name: Fluent.Reader.Unpacked.${{ steps.package-version.outputs.current-version }}.x86.zip - asset_content_type: application/zip + - name: Upload x64 zip to release assets + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./bin/win32/x64/Fluent Reader-${{ steps.package-version.outputs.current-version }}-win.zip + asset_name: Fluent.Reader.Unpacked.${{ steps.package-version.outputs.current-version }}.x64.zip + asset_content_type: application/zip + + - name: Upload x86 zip to release assets + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./bin/win32/ia32/Fluent Reader-${{ steps.package-version.outputs.current-version }}-ia32-win.zip + asset_name: Fluent.Reader.Unpacked.${{ steps.package-version.outputs.current-version }}.x86.zip + asset_content_type: application/zip diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..3207dc0 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,12 @@ +node_modules +dist/**/*.js +dist/**/*.js.map +bin/* +.DS_Store +*.provisionprofile +*.lock + +*.html +*.md +*.json +!src/**/*.json diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 0000000..5aedd03 --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1,5 @@ +tabWidth: 4 +semi: false +jsxBracketSameLine: true +arrowParens: "avoid" +quoteProps: "consistent" diff --git a/dist/article/article.css b/dist/article/article.css index ebbf632..3081e3e 100644 --- a/dist/article/article.css +++ b/dist/article/article.css @@ -1,7 +1,9 @@ @import "../styles/scroll.css"; -html, body { - font-family: "Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei", sans-serif; +html, +body { + font-family: "Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei", + sans-serif; } html { overflow: hidden scroll; @@ -21,14 +23,22 @@ html { } } -h1, h2, h3, h4, h5, h6, b, strong { +h1, +h2, +h3, +h4, +h5, +h6, +b, +strong { font-weight: 600; } a { color: var(--primary); text-decoration: none; } -a:hover, a:active { +a:hover, +a:active { color: var(--primary-alt); text-decoration: underline; } @@ -64,7 +74,7 @@ a:hover, a:active { } #main > p.date { color: var(--gray); - font-size: .875rem; + font-size: 0.875rem; } article { @@ -81,7 +91,7 @@ article figure { text-align: center; } article figure figcaption { - font-size: .875rem; + font-size: 0.875rem; color: var(--gray); -webkit-user-modify: read-only; } @@ -90,11 +100,11 @@ article iframe { } article code { font-family: Monaco, Consolas, monospace; - font-size: .875rem; + font-size: 0.875rem; line-height: 1; } article blockquote { border-left: 2px solid var(--gray); margin: 1em 0; padding: 0 40px; -} \ No newline at end of file +} diff --git a/dist/styles/cards.css b/dist/styles/cards.css index ca523fc..9734a72 100644 --- a/dist/styles/cards.css +++ b/dist/styles/cards.css @@ -30,7 +30,8 @@ font-size: 12px; } -.read-indicator, .starred-indicator { +.read-indicator, +.starred-indicator { display: block; width: 16px; height: 16px; @@ -99,14 +100,15 @@ background-color: var(--white); box-shadow: #0004 0 5px 20px; margin: 18px 12px; - transition: box-shadow linear .08s, transform linear .08s; + transition: box-shadow linear 0.08s, transform linear 0.08s; animation-fill-mode: none; } -.default-card:hover, .ms-Fabric--isFocusVisible .default-card:focus { +.default-card:hover, +.ms-Fabric--isFocusVisible .default-card:focus { box-shadow: #0006 0 5px 40px; } .default-card:active { - transform: scale(.97); + transform: scale(0.97); box-shadow: #0004 0 5px 20px; } @@ -132,10 +134,14 @@ height: 144px; -webkit-user-drag: none; } -.default-card img.head, .default-card p, .default-card h3 { - transition: transform ease-out .12s; +.default-card img.head, +.default-card p, +.default-card h3 { + transition: transform ease-out 0.12s; } -.default-card.transform:hover img.head, .default-card.transform:hover p, .default-card.transform:hover h3, +.default-card.transform:hover img.head, +.default-card.transform:hover p, +.default-card.transform:hover h3, .ms-Fabric--isFocusVisible .default-card.transform:focus img.head, .ms-Fabric--isFocusVisible .default-card.transform:focus p, .ms-Fabric--isFocusVisible .default-card.transform:focus h3 { @@ -172,11 +178,12 @@ .list-card { display: flex; - transition: box-shadow linear .08s; + transition: box-shadow linear 0.08s; border-bottom: 1px solid var(--neutralQuaternaryAlt); box-shadow: #0000 0 5px 15px; } -.list-card:hover, .ms-Fabric--isFocusVisible .list-card:focus { +.list-card:hover, +.ms-Fabric--isFocusVisible .list-card:focus { box-shadow: #0004 0 5px 15px; } .list-card:active { @@ -230,7 +237,8 @@ height: 100%; border-left: 2px solid var(--primary); } -.list-card.read, .list-card.read p.snippet { +.list-card.read, +.list-card.read p.snippet { color: var(--neutralSecondaryAlt); } @@ -239,20 +247,22 @@ padding: 24px; max-height: 160px; display: flex; - transition: box-shadow linear .08s, background-color linear .08s, transform linear .08s; + transition: box-shadow linear 0.08s, background-color linear 0.08s, + transform linear 0.08s; border-bottom: 1px solid var(--neutralQuaternaryAlt); box-shadow: #0000 0 5px 20px; } .magazine-card.read { color: var(--neutralSecondaryAlt); } -.magazine-card:hover, .ms-Fabric--isFocusVisible .magazine-card:focus { +.magazine-card:hover, +.ms-Fabric--isFocusVisible .magazine-card:focus { box-shadow: #0004 0 5px 20px; background-color: var(--white); } .magazine-card:active { box-shadow: #0000 0 5px 20px; - transform: scale(.97); + transform: scale(0.97); background-color: unset; } .magazine-card div.head { @@ -279,7 +289,8 @@ height: 16px; margin: 0; } -.magazine-card h3.title, .magazine-card p.snippet { +.magazine-card h3.title, +.magazine-card p.snippet { overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; @@ -304,9 +315,10 @@ font-size: 14px; line-height: 31px; padding: 0 9px; - transition: box-shadow linear .08s, background-color linear .08s; + transition: box-shadow linear 0.08s, background-color linear 0.08s; } -.compact-card:hover, .ms-Fabric--isFocusVisible .compact-card:focus { +.compact-card:hover, +.ms-Fabric--isFocusVisible .compact-card:focus { box-shadow: #0004 0 0 10px; background-color: var(--white); } @@ -346,4 +358,4 @@ } .compact-card .time { font-size: 12px; -} \ No newline at end of file +} diff --git a/dist/styles/dark.css b/dist/styles/dark.css index 10526d5..0800f10 100644 --- a/dist/styles/dark.css +++ b/dist/styles/dark.css @@ -2,10 +2,12 @@ .ms-Button--commandBar.active .ms-Button-icon { color: #c7e0f4; } - .btn-group .btn:hover, .ms-Nav-compositeLink:hover { + .btn-group .btn:hover, + .ms-Nav-compositeLink:hover { background-color: #fff1; } - .btn-group .btn:active, .ms-Nav-compositeLink:active { + .btn-group .btn:active, + .ms-Nav-compositeLink:active { background-color: #fff2; } .settings .loading { @@ -14,28 +16,32 @@ .default-card { box-shadow: #0006 0px 5px 20px; } - .default-card:hover, .ms-Fabric--isFocusVisible .default-card:focus { + .default-card:hover, + .ms-Fabric--isFocusVisible .default-card:focus { box-shadow: #0008 0px 5px 40px; } .default-card div.bg { background-color: #000b; } - .list-card:hover, .ms-Fabric--isFocusVisible .list-card:focus { + .list-card:hover, + .ms-Fabric--isFocusVisible .list-card:focus { box-shadow: #0006 0px 5px 15px; } .list-card:active { box-shadow: #0000 0px 5px 15px, inset #0006 0px 0px 15px; } - .magazine-card:hover, .ms-Fabric--isFocusVisible .magazine-card:focus { + .magazine-card:hover, + .ms-Fabric--isFocusVisible .magazine-card:focus { box-shadow: #0006 0px 5px 20px; } .magazine-card:active { box-shadow: #0000 0px 5px 20px; } - .compact-card:hover, .ms-Fabric--isFocusVisible .compact-card:focus { + .compact-card:hover, + .ms-Fabric--isFocusVisible .compact-card:focus { box-shadow: #0008 0 0 10px; } .compact-card:active { box-shadow: #0000 0 0 10px; } -} \ No newline at end of file +} diff --git a/dist/styles/feeds.css b/dist/styles/feeds.css index d826ee3..1fb6d75 100644 --- a/dist/styles/feeds.css +++ b/dist/styles/feeds.css @@ -1,13 +1,18 @@ @keyframes slideUp20 { - 0% { transform: translateY(20px); } - 100% { transform: translateY(0); } + 0% { + transform: translateY(20px); + } + 100% { + transform: translateY(0); + } } .article-wrapper { margin: 32px auto 0; width: 860px; height: calc(100% - 50px); background-color: var(--white); - box-shadow: 0 6.4px 14.4px 0 rgba(0,0,0,.132), 0 1.2px 3.6px 0 rgba(0,0,0,.108); + box-shadow: 0 6.4px 14.4px 0 rgba(0, 0, 0, 0.132), + 0 1.2px 3.6px 0 rgba(0, 0, 0, 0.108); border-radius: 5px; overflow: hidden; animation-name: slideUp20; @@ -17,7 +22,7 @@ } .article-container .btn-group { position: absolute; - top: calc(50% - 32px) + top: calc(50% - 32px); } .article-container .btn-group.prev { left: calc(50% - 486px); @@ -29,7 +34,8 @@ height: 100%; user-select: none; } -.article webview, .article .error-prompt { +.article webview, +.article .error-prompt { width: 100%; height: calc(100% - 36px); border: none; @@ -45,7 +51,8 @@ color: var(--black); border-bottom: 1px solid var(--neutralQuaternaryAlt); } -.article .actions .favicon, .article .actions .ms-Spinner { +.article .actions .favicon, +.article .actions .ms-Spinner { margin: 8px 8px 11px 0; } .article .actions .ms-Spinner { @@ -70,7 +77,8 @@ content: "/"; margin: 0 6px; } -.side-article-wrapper, .side-logo-wrapper { +.side-article-wrapper, +.side-logo-wrapper { flex-grow: 1; padding-top: var(--navHeight); height: calc(100% - var(--navHeight)); @@ -108,7 +116,8 @@ .side-article-wrapper .article > .ms-Stack { border-top: 1px solid var(--neutralQuaternaryAlt); } -.list-feed-container:first-child::before, .side-article-wrapper::before { +.list-feed-container:first-child::before, +.side-article-wrapper::before { content: ""; display: block; width: 100%; @@ -156,7 +165,8 @@ padding: 16px 0; } -.magazine-feed, .compact-feed { +.magazine-feed, +.compact-feed { padding-top: 28px; height: calc(100% - 60px); overflow: hidden scroll; @@ -184,7 +194,8 @@ justify-content: space-around; flex-wrap: wrap; } -.cards-feed-container > div.load-more-wrapper, .flex-fix { +.cards-feed-container > div.load-more-wrapper, +.flex-fix { text-align: center; } .cards-feed-container > div.load-more-wrapper { @@ -206,4 +217,4 @@ color: var(--neutralSecondary); font-size: 14px; user-select: none; -} \ No newline at end of file +} diff --git a/dist/styles/global.css b/dist/styles/global.css index b473fec..07bb233 100644 --- a/dist/styles/global.css +++ b/dist/styles/global.css @@ -46,14 +46,17 @@ body.darwin { --navHeight: 38px; } -html, body { +html, +body { background-color: transparent; - font-family: "Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei", sans-serif; + font-family: "Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei", + sans-serif; height: 100%; overflow: hidden; margin: 0; } -body.win32, body.linux { +body.win32, +body.linux { background-color: var(--neutralLighterAlt); } #root { @@ -63,12 +66,15 @@ body.win32, body.linux { .ms-Link { user-select: none; } -.ms-ContextualMenu-link, .ms-Button, .ms-ContextualMenu-item button { +.ms-ContextualMenu-link, +.ms-Button, +.ms-ContextualMenu-item button { cursor: default; font-size: 13px; user-select: none; } -.ms-Nav-link, .ms-Nav-chevronButton { +.ms-Nav-link, +.ms-Nav-chevronButton { font-size: 12px; line-height: 32px; height: 32px; @@ -105,13 +111,16 @@ i.ms-Nav-chevron { .ms-Nav-groupContent { margin-bottom: 24px; } -.ms-ActivityItem-activityTypeIcon, .ms-ActivityItem-timeStamp { +.ms-ActivityItem-activityTypeIcon, +.ms-ActivityItem-timeStamp { user-select: none; } -.ms-Label, .ms-Spinner-label { +.ms-Label, +.ms-Spinner-label { user-select: none; } -.ms-ActivityItem, .ms-ActivityItem-commentText { +.ms-ActivityItem, +.ms-ActivityItem-commentText { color: var(--neutralSecondary); } .ms-ActivityItem-timeStamp { @@ -135,7 +144,8 @@ i.ms-Nav-chevron { user-select: none; overflow: hidden; } -#root > nav .btn, #root > nav span { +#root > nav .btn, +#root > nav span { z-index: 1; position: relative; } @@ -203,7 +213,8 @@ body.darwin .btn-group .seperator { font-size: 14px; vertical-align: top; } -#root > nav .btn-group .btn, .menu .btn-group .btn { +#root > nav .btn-group .btn, +.menu .btn-group .btn { height: var(--navHeight); line-height: var(--navHeight); } @@ -223,16 +234,19 @@ nav.hide-btns .btn-group .btn.system { nav.item-on .btn-group .btn.system { color: var(--whiteConstant); } -.btn-group .btn:hover, .ms-Nav-compositeLink:hover { +.btn-group .btn:hover, +.ms-Nav-compositeLink:hover { background-color: #0001; } -.btn-group .btn:active, .ms-Nav-compositeLink:active { +.btn-group .btn:active, +.ms-Nav-compositeLink:active { background-color: #0002; } .ms-Nav-compositeLink:hover .ms-Nav-link { background: none; } -.btn-group .btn.disabled, .btn-group .btn.fetching { +.btn-group .btn.disabled, +.btn-group .btn.fetching { background-color: unset !important; color: var(--neutralSecondaryAlt); } @@ -240,8 +254,12 @@ nav.item-on .btn-group .btn.system { animation: rotating linear 1.5s infinite; } @keyframes rotating { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } } .btn-group .btn.close:hover { background-color: #e81123; @@ -251,9 +269,9 @@ nav.item-on .btn-group .btn.system { background-color: #f1707a; color: var(--whiteConstant) !important; } -.btn-group .btn.inline-block-wide { +.btn-group .btn.inline-block-wide { display: none; } body.darwin .btn-group .btn.system { display: none; -} \ No newline at end of file +} diff --git a/dist/styles/main.css b/dist/styles/main.css index d6b5a23..26aab7b 100644 --- a/dist/styles/main.css +++ b/dist/styles/main.css @@ -6,10 +6,15 @@ } @keyframes fade { - 0% { opacity: 0; } - 100% { opacity: 1; } + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } } -.menu-container, .article-container { +.menu-container, +.article-container { position: fixed; z-index: 5; left: 0; @@ -22,7 +27,9 @@ animation-name: fade; background-color: #0008; } -.menu-container, .article-container, .article-wrapper { +.menu-container, +.article-container, +.article-wrapper { animation-duration: 0.5s; animation-timing-function: var(--transition-timing); animation-fill-mode: both; @@ -45,7 +52,8 @@ background-color: var(--neutralLighterAltOpacity); backdrop-filter: var(--blur); box-shadow: 5px 0 25px #0004; - transition: clip-path var(--transition-timing) .367s, opacity cubic-bezier(0, 0, 0.2, 1) .367s; + transition: clip-path var(--transition-timing) 0.367s, + opacity cubic-bezier(0, 0, 0.2, 1) 0.367s; clip-path: inset(0 100% 0 0); opacity: 0; } @@ -102,7 +110,8 @@ body.darwin .menu .btn-group { width: 680px; height: calc(100% - 64px); background-color: var(--white); - box-shadow: 0 6.4px 14.4px 0 rgba(0,0,0,.132), 0 1.2px 3.6px 0 rgba(0,0,0,.108); + box-shadow: 0 6.4px 14.4px 0 rgba(0, 0, 0, 0.132), + 0 1.2px 3.6px 0 rgba(0, 0, 0, 0.108); overflow: hidden; } div[role="toolbar"] { @@ -212,7 +221,7 @@ img.favicon.dropdown { .article-search { z-index: 4; position: absolute; - top:0; + top: 0; left: 36px; width: 100%; max-width: calc(100% - 484px); @@ -220,7 +229,8 @@ img.favicon.dropdown { border: none; -webkit-app-region: none; height: calc(var(--navHeight) - 4px); - box-shadow: 0 1.6px 3.6px 0 rgba(0,0,0,.132), 0 0.3px 0.9px 0 rgba(0,0,0,.108); + box-shadow: 0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), + 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108); } body.darwin.not-fullscreen .article-search { left: 108px; @@ -236,8 +246,9 @@ body.darwin .list-main .article-search { top: var(--navHeight); margin: 0 10px; } -.main, .list-main { - transition: margin-left var(--transition-timing) .367s; +.main, +.list-main { + transition: margin-left var(--transition-timing) 0.367s; margin-left: 0; } @@ -245,7 +256,8 @@ body.darwin .list-main .article-search { #root > nav.menu-on { padding-left: 296px; } - #root > nav.menu-on span.title, body.darwin #root > nav.menu-on span.title { + #root > nav.menu-on span.title, + body.darwin #root > nav.menu-on span.title { max-width: 300px; } nav.menu-on .btn-group .btn { @@ -283,7 +295,8 @@ body.darwin .list-main .article-search { height: 120%; box-shadow: inset 5px 0 25px #0004; } - .main.menu-on, .list-main.menu-on { + .main.menu-on, + .list-main.menu-on { margin-left: 280px; } .menu-on .article-search { @@ -303,10 +316,12 @@ body.darwin .list-main .article-search { top: 4px; } - nav.hide-btns .btn-group .btn, nav.menu-on .btn-group .btn.hide-wide, .menu .btn-group .btn.hide-wide { + nav.hide-btns .btn-group .btn, + nav.menu-on .btn-group .btn.hide-wide, + .menu .btn-group .btn.hide-wide { display: none; } .btn-group .btn.inline-block-wide { display: inline-block; } -} \ No newline at end of file +} diff --git a/docs/styles.css b/docs/styles.css index 96a5120..bada4fc 100644 --- a/docs/styles.css +++ b/docs/styles.css @@ -1,4 +1,5 @@ -html, body { +html, +body { background-color: #f3f2f1; font-family: "Segoe UI", "Microsoft YaHei", sans-serif; margin: 0; @@ -13,13 +14,15 @@ a { color: #0078d4; text-decoration: none; } -a:hover, a:active { +a:hover, +a:active { color: #004578; text-decoration: underline; } .elevate { - box-shadow: 0 6.4px 14.4px 0 rgba(0,0,0,.132), 0 1.2px 3.6px 0 rgba(0,0,0,.108); + box-shadow: 0 6.4px 14.4px 0 rgba(0, 0, 0, 0.132), + 0 1.2px 3.6px 0 rgba(0, 0, 0, 0.108); } .logo-container { @@ -67,14 +70,16 @@ a:hover, a:active { position: relative; top: -280px; } -.light-container h1, .dark-container h1 { +.light-container h1, +.dark-container h1 { width: 95%; max-width: 800px; margin: 48px auto 24px; font-weight: 500; text-align: center; } -.light-container p, .dark-container p { +.light-container p, +.dark-container p { width: 85%; max-width: 750px; margin: 24px auto; @@ -108,7 +113,7 @@ a:hover, a:active { .features-container > section > h3 { font-weight: 500; color: #605e5c; - margin: 0 0 .5em; + margin: 0 0 0.5em; } .features-container > section > h3 > span { color: #d2d0ce; @@ -170,13 +175,16 @@ a:hover, a:active { justify-content: center; margin: calc(50vh - 210px) 0 48px; } -.links > a { +.links > a { display: inline-block; margin: 0 8px; } @media (max-width: 780px) { - html, body { font-size: 14px; } + html, + body { + font-size: 14px; + } .logo-container img { height: 140px; width: 140px; diff --git a/electron-builder-mas.yml b/electron-builder-mas.yml index c6d8681..de4586a 100644 --- a/electron-builder-mas.yml +++ b/electron-builder-mas.yml @@ -3,33 +3,33 @@ buildVersion: 24 productName: Fluent Reader copyright: Copyright © 2020 Haoyuan Liu files: - - "./dist/**/*" - - "!**/*.js.map" + - "./dist/**/*" + - "!**/*.js.map" directories: - output: "./bin/${platform}/${arch}/" + output: "./bin/${platform}/${arch}/" mac: - darkModeSupport: true - target: - - dmg - category: public.app-category.news - electronLanguages: - - zh_CN - - zh_TW - - en - - fr - - es - - de - - tr - - ja - - sv - - uk - - it - - nl - minimumSystemVersion: 10.14.0 + darkModeSupport: true + target: + - dmg + category: public.app-category.news + electronLanguages: + - zh_CN + - zh_TW + - en + - fr + - es + - de + - tr + - ja + - sv + - uk + - it + - nl + minimumSystemVersion: 10.14.0 mas: - entitlements: build/entitlements.mas.plist - entitlementsInherit: build/entitlements.mas.inherit.plist - provisioningProfile: build/embedded.provisionprofile - hardenedRuntime: false - gatekeeperAssess: false - asarUnpack: [] + entitlements: build/entitlements.mas.plist + entitlementsInherit: build/entitlements.mas.inherit.plist + provisioningProfile: build/embedded.provisionprofile + hardenedRuntime: false + gatekeeperAssess: false + asarUnpack: [] diff --git a/electron-builder.yml b/electron-builder.yml index bf4d3e7..74e3788 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -2,61 +2,61 @@ appId: me.hyliu.fluentreader productName: Fluent Reader copyright: Copyright © 2020 Haoyuan Liu files: - - "./dist/**/*" - - "!**/*.js.map" + - "./dist/**/*" + - "!**/*.js.map" directories: - output: "./bin/${platform}/${arch}/" + output: "./bin/${platform}/${arch}/" mac: - darkModeSupport: true - target: - - dmg - category: public.app-category.news - electronLanguages: - - zh_CN - - zh_TW - - en - - fr - - es - - de - - tr - - ja - - sv - - uk - - it - - nl + darkModeSupport: true + target: + - dmg + category: public.app-category.news + electronLanguages: + - zh_CN + - zh_TW + - en + - fr + - es + - de + - tr + - ja + - sv + - uk + - it + - nl win: - target: - - nsis - - zip + target: + - nsis + - zip appx: - applicationId: FluentReader - identityName: 25286HaoyuanLiu.FluentReader - publisher: CN=FD70E7FA-E5AC-41C4-B9C4-6E8708A6616A - backgroundColor: transparent - languages: - - zh-CN - - zh-TW - - en-US - - fr-FR - - es - - de - - tr - - ja - - sv - - uk - - it - - nl - showNameOnTiles: true - setBuildNumber: true + applicationId: FluentReader + identityName: 25286HaoyuanLiu.FluentReader + publisher: CN=FD70E7FA-E5AC-41C4-B9C4-6E8708A6616A + backgroundColor: transparent + languages: + - zh-CN + - zh-TW + - en-US + - fr-FR + - es + - de + - tr + - ja + - sv + - uk + - it + - nl + showNameOnTiles: true + setBuildNumber: true nsis: - oneClick: false - perMachine: true - allowToChangeInstallationDirectory: true - deleteAppDataOnUninstall: true + oneClick: false + perMachine: true + allowToChangeInstallationDirectory: true + deleteAppDataOnUninstall: true linux: - target: - - AppImage - icon: build/icons - category: Utility - desktop: - StartupWMClass: fluent-reader + target: + - AppImage + icon: build/icons + category: Utility + desktop: + StartupWMClass: fluent-reader diff --git a/package-lock.json b/package-lock.json index 9b2ecb9..36ba296 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "js-md5": "^0.7.3", "lovefield": "^2.1.12", "nedb": "^1.8.0", + "prettier": "2.3.2", "qrcode.react": "^1.0.0", "react": "^16.13.1", "react-dom": "^16.13.1", @@ -35,7 +36,7 @@ "redux-thunk": "^2.3.0", "reselect": "^4.0.0", "ts-loader": "^7.0.4", - "typescript": "^3.9.2", + "typescript": "^4.3.5", "webpack": "^4.43.0", "webpack-cli": "^3.3.11" } @@ -105,15 +106,15 @@ } }, "node_modules/@electron/universal/node_modules/fs-extra": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", - "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", - "universalify": "^1.0.0" + "universalify": "^2.0.0" }, "engines": { "node": ">=10" @@ -125,23 +126,16 @@ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.6", "universalify": "^2.0.0" - } - }, - "node_modules/@electron/universal/node_modules/jsonfile/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, "node_modules/@electron/universal/node_modules/universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true, "engines": { "node": ">= 10.0.0" @@ -204,10 +198,20 @@ } }, "node_modules/@malept/cross-spawn-promise": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.0.tgz", - "integrity": "sha512-GeIK5rfU1Yd7BZJQPTGZMMmcZy5nhRToPXZcjaDwQDRSewdhp648GT2E4dh+L7+Io7AOW6WQ+GR44QSzja4qxg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", + "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], "dependencies": { "cross-spawn": "^7.0.1" }, @@ -359,24 +363,27 @@ "dev": true }, "node_modules/@types/debug": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", - "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", - "dev": true + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dev": true, + "dependencies": { + "@types/ms": "*" + } }, "node_modules/@types/fs-extra": { - "version": "9.0.11", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.11.tgz", - "integrity": "sha512-mZsifGG4QeQ7hlkhO56u7zt/ycBgGxSVsFI/6lGTU34VtwkiqrrSDgw0+ygs8kFGWcXnFQWMrzF2h7TtDFNixA==", + "version": "9.0.12", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.12.tgz", + "integrity": "sha512-I+bsBr67CurCGnSenZZ7v94gd3tc3+Aj2taxMT4yu4ABLuOgOjeFxX3dokG24ztSRg5tnT00sL8BszO7gSMoIw==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", "dev": true, "optional": true, "dependencies": { @@ -407,12 +414,18 @@ "dev": true }, "node_modules/@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "dev": true, "optional": true }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", + "dev": true + }, "node_modules/@types/nedb": { "version": "1.8.9", "resolved": "https://registry.npmjs.org/@types/nedb/-/nedb-1.8.9.tgz", @@ -498,9 +511,9 @@ } }, "node_modules/@types/verror": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.4.tgz", - "integrity": "sha512-OjJdqx6QlbyZw9LShPwRW+Kmiegeg3eWNI41MQQKaG3vjdU2L9SRElntM51HmHBY1cu7izxQJ1lMYioQh3XMBg==", + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.5.tgz", + "integrity": "sha512-9UjMCHK5GPgQRoNbqdLIAvAy0EInuiqbW0PBMtVP6B5B2HQJlvoJHM+KodPZMEjOa5VkSc+5LH7xy+cUzQdmHw==", "dev": true, "optional": true }, @@ -539,18 +552,18 @@ } }, "node_modules/@types/yargs": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", - "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.2.tgz", + "integrity": "sha512-JhZ+pNdKMfB0rXauaDlrIvm+U7V4m03PPOSVoPS66z8gf+G4Z/UW8UlrVIj2MRQOBzuoEvYtjS0bqYwnpZaS9Q==", "dev": true, "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", "dev": true }, "node_modules/@uifabric/foundation": { @@ -928,15 +941,15 @@ } }, "node_modules/app-builder-bin": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.5.13.tgz", - "integrity": "sha512-ighVe9G+bT1ENGdp9ecO1P+94vv/f+FUwaI+XkNzeg9bYF8Oi3BQ+mJuxS00UgyHs8luuOzjzC+qnAtdb43Mpg==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.7.1.tgz", + "integrity": "sha512-ql93vEUq6WsstGXD+SBLSIQw6SNnhbDEM0swzgugytMxLp3rT24Ag/jcC80ZHxiPRTdew1niuR7P3/FCrDqIjw==", "dev": true }, "node_modules/app-builder-lib": { - "version": "22.11.3", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.11.3.tgz", - "integrity": "sha512-u40ESAF/wPVlRPkS0hRjtClzUcS0PQ61bb5ZN8+d039cmwtS7myRVYucck58c9GOyXfvyO1hHaJii5I+QrBtdA==", + "version": "22.12.0", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.12.0.tgz", + "integrity": "sha512-VsBCb3zkY1ugdFxKHF31gxrJipFAf+cDE74XfPwxM4Jrb+QblQX8YRO2Cl268TZrhBEcVnBKIrx9aSnvMbBVgw==", "dev": true, "dependencies": { "@develar/schema-utils": "~2.6.5", @@ -945,18 +958,19 @@ "7zip-bin": "~5.1.1", "async-exit-hook": "^2.0.1", "bluebird-lst": "^1.0.9", - "builder-util": "22.11.3", - "builder-util-runtime": "8.7.5", + "builder-util": "22.11.11", + "builder-util-runtime": "8.7.10", "chromium-pickle-js": "^0.2.0", "debug": "^4.3.2", "ejs": "^3.1.6", - "electron-publish": "22.11.2", + "electron-osx-sign": "^0.5.0", + "electron-publish": "22.11.11", "fs-extra": "^10.0.0", "hosted-git-info": "^4.0.2", "is-ci": "^3.0.0", "isbinaryfile": "^4.0.8", "js-yaml": "^4.1.0", - "lazy-val": "^1.0.4", + "lazy-val": "^1.0.5", "minimatch": "^3.0.4", "read-config-file": "6.2.0", "sanitize-filename": "^1.6.3", @@ -964,7 +978,7 @@ "temp-file": "^3.4.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/app-builder-lib/node_modules/fs-extra": { @@ -1678,6 +1692,22 @@ "isarray": "^1.0.0" } }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -1696,6 +1726,12 @@ "node": ">=0.4.0" } }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, "node_modules/buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -1709,17 +1745,17 @@ "dev": true }, "node_modules/builder-util": { - "version": "22.11.3", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.11.3.tgz", - "integrity": "sha512-az4s7iyf1ZPXaSVgCY+YoUcBVNspHz/f2lZSXTeXpPUjiKcbV+jzewWdw8yPWFUZ9UDArI5AVhW2bQfyBRjgVQ==", + "version": "22.11.11", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.11.11.tgz", + "integrity": "sha512-2UJjOuPXhix68mmQ9hkv9G52Y0EVB8RPjlJF61jr3/tLIyd3UiJmEEhKttu8F+JVHKj8myz1MWw2/keJE/Nh+w==", "dev": true, "dependencies": { - "@types/debug": "^4.1.5", + "@types/debug": "^4.1.6", "@types/fs-extra": "^9.0.11", "7zip-bin": "~5.1.1", - "app-builder-bin": "3.5.13", + "app-builder-bin": "3.7.1", "bluebird-lst": "^1.0.9", - "builder-util-runtime": "8.7.5", + "builder-util-runtime": "8.7.10", "chalk": "^4.1.1", "debug": "^4.3.2", "fs-extra": "^10.0.0", @@ -1731,9 +1767,9 @@ } }, "node_modules/builder-util-runtime": { - "version": "8.7.5", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.5.tgz", - "integrity": "sha512-fgUFHKtMNjdvH6PDRFntdIGUPgwZ69sXsAqEulCtoiqgWes5agrMq/Ud274zjJRTbckYh2PHh8/1CpFc6dpsbQ==", + "version": "8.7.10", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.10.tgz", + "integrity": "sha512-zelTRebsOsj33pF+Jf/qwpvx9W6CeMQshqaRa70Ii6+NQGsspMXqlKDQb+1lvTv9aWARxa3+jy/syzm8jTE8Kw==", "dev": true, "dependencies": { "debug": "^4.3.2", @@ -1759,9 +1795,9 @@ } }, "node_modules/builder-util/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { "ansi-styles": "^4.1.0", @@ -2209,6 +2245,15 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "node_modules/colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -2224,6 +2269,15 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "node_modules/compare-version": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", + "integrity": "sha1-AWLsLZNR9d3VmpICy6k1NmpyUIA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -2786,15 +2840,6 @@ "dircompare": "src/cli/dircompare.js" } }, - "node_modules/dir-compare/node_modules/colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/dir-compare/node_modules/commander": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", @@ -2808,20 +2853,20 @@ } }, "node_modules/dmg-builder": { - "version": "22.11.3", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.11.3.tgz", - "integrity": "sha512-NGlorMQF2YGboVtHM8zP5EHxYhrxFGjtsnX6YCr9BV1bsjSPVyBJZpuxKnOOLj86zlYWYeiNGyj4NeUOLGgUCA==", + "version": "22.12.0", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.12.0.tgz", + "integrity": "sha512-5MANoNVctpiN536BLNDQp/gDk2BLRe23LE+RbOSt3I8b65V6mtvekjNiyUU5M+/UAbAzCcOZcCcaV3jDBuapaw==", "dev": true, "dependencies": { - "app-builder-lib": "22.11.3", - "builder-util": "22.11.3", - "builder-util-runtime": "8.7.5", + "app-builder-lib": "22.12.0", + "builder-util": "22.11.11", + "builder-util-runtime": "8.7.10", "fs-extra": "^10.0.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" }, "optionalDependencies": { - "dmg-license": "^1.0.8" + "dmg-license": "^1.0.9" } }, "node_modules/dmg-builder/node_modules/fs-extra": { @@ -3049,21 +3094,20 @@ } }, "node_modules/electron-builder": { - "version": "22.11.3", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.11.3.tgz", - "integrity": "sha512-STv4uU3q00FzVgW9kMpRXSrhJxogzAZgIhFZl0mBZQC1VOAajNiEBsZPaU32jP23oxlgLQExj/ux6/frYk5vGA==", + "version": "22.12.0", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.12.0.tgz", + "integrity": "sha512-X6YA0R6oYsS2iy+u0w3Sdm7u9rTo4JggD/jabKG34nZ0Hs5/iPAHBkcVvXqiFdMvnywbh1jm/aaf4PWW6XNMHw==", "dev": true, - "license": "MIT", "dependencies": { - "@types/yargs": "^16.0.1", - "app-builder-lib": "22.11.3", - "builder-util": "22.11.3", - "builder-util-runtime": "8.7.5", + "@types/yargs": "^17.0.1", + "app-builder-lib": "22.12.0", + "builder-util": "22.11.11", + "builder-util-runtime": "8.7.10", "chalk": "^4.1.1", - "dmg-builder": "22.11.3", + "dmg-builder": "22.12.0", "fs-extra": "^10.0.0", "is-ci": "^3.0.0", - "lazy-val": "^1.0.4", + "lazy-val": "^1.0.5", "read-config-file": "6.2.0", "update-notifier": "^5.1.0", "yargs": "^17.0.1" @@ -3073,7 +3117,7 @@ "install-app-deps": "install-app-deps.js" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/electron-builder/node_modules/ansi-regex": { @@ -3295,19 +3339,67 @@ "node": ">=10" } }, - "node_modules/electron-publish": { - "version": "22.11.2", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.11.2.tgz", - "integrity": "sha512-RSrDyYL407QRryIN0QhQGJc5PjHK4gdCwTHYTH5Zl43753ZLVUMRmzW768H0Tb8hVM2VOymy8pNnQAHB5egoiQ==", + "node_modules/electron-osx-sign": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.5.0.tgz", + "integrity": "sha512-icoRLHzFz/qxzDh/N4Pi2z4yVHurlsCAYQvsCSG7fCedJ4UJXBS6PoQyGH71IfcqKupcKeK7HX/NkyfG+v6vlQ==", "dev": true, "dependencies": { - "@types/fs-extra": "^9.0.7", - "builder-util": "22.11.2", - "builder-util-runtime": "8.7.4", - "chalk": "^4.1.0", - "fs-extra": "^9.1.0", - "lazy-val": "^1.0.4", - "mime": "^2.5.0" + "bluebird": "^3.5.0", + "compare-version": "^0.1.2", + "debug": "^2.6.8", + "isbinaryfile": "^3.0.2", + "minimist": "^1.2.0", + "plist": "^3.0.1" + }, + "bin": { + "electron-osx-flat": "bin/electron-osx-flat.js", + "electron-osx-sign": "bin/electron-osx-sign.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/electron-osx-sign/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/electron-osx-sign/node_modules/isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "dependencies": { + "buffer-alloc": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/electron-osx-sign/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/electron-publish": { + "version": "22.11.11", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.11.11.tgz", + "integrity": "sha512-XINI2yz7DpForvLDENr1zfi6yW+O3ufeIgNCg/nkqiD3tBM44AokgY3aYURzsi93ZwFscoQkR2LhmHDvn30oAw==", + "dev": true, + "dependencies": { + "@types/fs-extra": "^9.0.11", + "builder-util": "22.11.11", + "builder-util-runtime": "8.7.10", + "chalk": "^4.1.1", + "fs-extra": "^10.0.0", + "lazy-val": "^1.0.5", + "mime": "^2.5.2" } }, "node_modules/electron-publish/node_modules/ansi-styles": { @@ -3325,45 +3417,10 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/electron-publish/node_modules/builder-util": { - "version": "22.11.2", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.11.2.tgz", - "integrity": "sha512-n5QkoRcNKy7KrBO8trpk7WRgdpBnOu68KVm+roSbDtZaW1qAmBplyThxnczcvjByVwD+UrsKd62eNIARiz2jyw==", - "dev": true, - "dependencies": { - "@types/debug": "^4.1.5", - "@types/fs-extra": "^9.0.7", - "7zip-bin": "~5.1.1", - "app-builder-bin": "3.5.13", - "bluebird-lst": "^1.0.9", - "builder-util-runtime": "8.7.4", - "chalk": "^4.1.0", - "debug": "^4.3.2", - "fs-extra": "^9.1.0", - "is-ci": "^3.0.0", - "js-yaml": "^4.0.0", - "source-map-support": "^0.5.19", - "stat-mode": "^1.0.0", - "temp-file": "^3.3.7" - } - }, - "node_modules/electron-publish/node_modules/builder-util-runtime": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.4.tgz", - "integrity": "sha512-2vDOwH0cyyCLQwW0Tsrg3RKKQpEcrV70KFun39E8RPzNFBOv9ds9juK8WUnO6ml+xJWKkKTjWLFdF3y+8GbPOw==", - "dev": true, - "dependencies": { - "debug": "^4.3.2", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/electron-publish/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { "ansi-styles": "^4.1.0", @@ -3395,18 +3452,17 @@ "dev": true }, "node_modules/electron-publish/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/electron-publish/node_modules/has-flag": { @@ -6524,15 +6580,14 @@ } }, "node_modules/plist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.2.tgz", - "integrity": "sha512-MSrkwZBdQ6YapHy87/8hDU8MnIcyxBKjeF+McXnr5A9MtffPewTs7G3hlpodT5TacyfIyFTaJEhh3GGcmasTgQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.3.tgz", + "integrity": "sha512-ghdOKN99hh1oEmAlwBmPYo4L+tSQ7O3jRpkhWqOrMz86CWotpVzMevvQ+czo7oPDpOZyA6K06Ci7QVHpoh9gaA==", "dev": true, - "optional": true, "dependencies": { "base64-js": "^1.5.1", "xmlbuilder": "^9.0.7", - "xmldom": "^0.5.0" + "xmldom": "^0.6.0" }, "engines": { "node": ">=6" @@ -6543,7 +6598,6 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", "dev": true, - "optional": true, "engines": { "node": ">=4.0" } @@ -6566,6 +6620,18 @@ "node": ">=4" } }, + "node_modules/prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/pretty-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", @@ -7397,9 +7463,9 @@ } }, "node_modules/smart-buffer": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", - "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true, "optional": true, "engines": { @@ -8177,9 +8243,9 @@ } }, "node_modules/typescript": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz", - "integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -9309,11 +9375,10 @@ } }, "node_modules/xmldom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.5.0.tgz", - "integrity": "sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.6.0.tgz", + "integrity": "sha512-iAcin401y58LckRZ0TkI4k0VSM1Qg0KGSc3i8rU+xrxe19A/BN1zHyVSJY7uoutVlaTSzYyk/v5AmkewAP7jtg==", "dev": true, - "optional": true, "engines": { "node": ">=10.0.0" } @@ -9430,15 +9495,15 @@ }, "dependencies": { "fs-extra": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", - "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", - "universalify": "^1.0.0" + "universalify": "^2.0.0" } }, "jsonfile": { @@ -9449,20 +9514,12 @@ "requires": { "graceful-fs": "^4.1.6", "universalify": "^2.0.0" - }, - "dependencies": { - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } } }, "universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true } } @@ -9524,9 +9581,9 @@ } }, "@malept/cross-spawn-promise": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.0.tgz", - "integrity": "sha512-GeIK5rfU1Yd7BZJQPTGZMMmcZy5nhRToPXZcjaDwQDRSewdhp648GT2E4dh+L7+Io7AOW6WQ+GR44QSzja4qxg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", + "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", "dev": true, "requires": { "cross-spawn": "^7.0.1" @@ -9645,24 +9702,27 @@ "dev": true }, "@types/debug": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", - "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", - "dev": true + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dev": true, + "requires": { + "@types/ms": "*" + } }, "@types/fs-extra": { - "version": "9.0.11", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.11.tgz", - "integrity": "sha512-mZsifGG4QeQ7hlkhO56u7zt/ycBgGxSVsFI/6lGTU34VtwkiqrrSDgw0+ygs8kFGWcXnFQWMrzF2h7TtDFNixA==", + "version": "9.0.12", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.12.tgz", + "integrity": "sha512-I+bsBr67CurCGnSenZZ7v94gd3tc3+Aj2taxMT4yu4ABLuOgOjeFxX3dokG24ztSRg5tnT00sL8BszO7gSMoIw==", "dev": true, "requires": { "@types/node": "*" } }, "@types/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", "dev": true, "optional": true, "requires": { @@ -9693,12 +9753,18 @@ "dev": true }, "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "dev": true, "optional": true }, + "@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", + "dev": true + }, "@types/nedb": { "version": "1.8.9", "resolved": "https://registry.npmjs.org/@types/nedb/-/nedb-1.8.9.tgz", @@ -9784,9 +9850,9 @@ } }, "@types/verror": { - "version": "1.10.4", - "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.4.tgz", - "integrity": "sha512-OjJdqx6QlbyZw9LShPwRW+Kmiegeg3eWNI41MQQKaG3vjdU2L9SRElntM51HmHBY1cu7izxQJ1lMYioQh3XMBg==", + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.5.tgz", + "integrity": "sha512-9UjMCHK5GPgQRoNbqdLIAvAy0EInuiqbW0PBMtVP6B5B2HQJlvoJHM+KodPZMEjOa5VkSc+5LH7xy+cUzQdmHw==", "dev": true, "optional": true }, @@ -9824,18 +9890,18 @@ } }, "@types/yargs": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", - "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.2.tgz", + "integrity": "sha512-JhZ+pNdKMfB0rXauaDlrIvm+U7V4m03PPOSVoPS66z8gf+G4Z/UW8UlrVIj2MRQOBzuoEvYtjS0bqYwnpZaS9Q==", "dev": true, "requires": { "@types/yargs-parser": "*" } }, "@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", "dev": true }, "@uifabric/foundation": { @@ -10200,15 +10266,15 @@ } }, "app-builder-bin": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.5.13.tgz", - "integrity": "sha512-ighVe9G+bT1ENGdp9ecO1P+94vv/f+FUwaI+XkNzeg9bYF8Oi3BQ+mJuxS00UgyHs8luuOzjzC+qnAtdb43Mpg==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.7.1.tgz", + "integrity": "sha512-ql93vEUq6WsstGXD+SBLSIQw6SNnhbDEM0swzgugytMxLp3rT24Ag/jcC80ZHxiPRTdew1niuR7P3/FCrDqIjw==", "dev": true }, "app-builder-lib": { - "version": "22.11.3", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.11.3.tgz", - "integrity": "sha512-u40ESAF/wPVlRPkS0hRjtClzUcS0PQ61bb5ZN8+d039cmwtS7myRVYucck58c9GOyXfvyO1hHaJii5I+QrBtdA==", + "version": "22.12.0", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.12.0.tgz", + "integrity": "sha512-VsBCb3zkY1ugdFxKHF31gxrJipFAf+cDE74XfPwxM4Jrb+QblQX8YRO2Cl268TZrhBEcVnBKIrx9aSnvMbBVgw==", "dev": true, "requires": { "@develar/schema-utils": "~2.6.5", @@ -10217,18 +10283,19 @@ "7zip-bin": "~5.1.1", "async-exit-hook": "^2.0.1", "bluebird-lst": "^1.0.9", - "builder-util": "22.11.3", - "builder-util-runtime": "8.7.5", + "builder-util": "22.11.11", + "builder-util-runtime": "8.7.10", "chromium-pickle-js": "^0.2.0", "debug": "^4.3.2", "ejs": "^3.1.6", - "electron-publish": "22.11.2", + "electron-osx-sign": "^0.5.0", + "electron-publish": "22.11.11", "fs-extra": "^10.0.0", "hosted-git-info": "^4.0.2", "is-ci": "^3.0.0", "isbinaryfile": "^4.0.8", "js-yaml": "^4.1.0", - "lazy-val": "^1.0.4", + "lazy-val": "^1.0.5", "minimatch": "^3.0.4", "read-config-file": "6.2.0", "sanitize-filename": "^1.6.3", @@ -10818,6 +10885,22 @@ "isarray": "^1.0.0" } }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -10830,6 +10913,12 @@ "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", "dev": true }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -10843,17 +10932,17 @@ "dev": true }, "builder-util": { - "version": "22.11.3", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.11.3.tgz", - "integrity": "sha512-az4s7iyf1ZPXaSVgCY+YoUcBVNspHz/f2lZSXTeXpPUjiKcbV+jzewWdw8yPWFUZ9UDArI5AVhW2bQfyBRjgVQ==", + "version": "22.11.11", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.11.11.tgz", + "integrity": "sha512-2UJjOuPXhix68mmQ9hkv9G52Y0EVB8RPjlJF61jr3/tLIyd3UiJmEEhKttu8F+JVHKj8myz1MWw2/keJE/Nh+w==", "dev": true, "requires": { - "@types/debug": "^4.1.5", + "@types/debug": "^4.1.6", "@types/fs-extra": "^9.0.11", "7zip-bin": "~5.1.1", - "app-builder-bin": "3.5.13", + "app-builder-bin": "3.7.1", "bluebird-lst": "^1.0.9", - "builder-util-runtime": "8.7.5", + "builder-util-runtime": "8.7.10", "chalk": "^4.1.1", "debug": "^4.3.2", "fs-extra": "^10.0.0", @@ -10874,9 +10963,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -10943,9 +11032,9 @@ } }, "builder-util-runtime": { - "version": "8.7.5", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.5.tgz", - "integrity": "sha512-fgUFHKtMNjdvH6PDRFntdIGUPgwZ69sXsAqEulCtoiqgWes5agrMq/Ud274zjJRTbckYh2PHh8/1CpFc6dpsbQ==", + "version": "8.7.10", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.10.tgz", + "integrity": "sha512-zelTRebsOsj33pF+Jf/qwpvx9W6CeMQshqaRa70Ii6+NQGsspMXqlKDQb+1lvTv9aWARxa3+jy/syzm8jTE8Kw==", "dev": true, "requires": { "debug": "^4.3.2", @@ -11260,6 +11349,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + }, "commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -11272,6 +11367,12 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "compare-version": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", + "integrity": "sha1-AWLsLZNR9d3VmpICy6k1NmpyUIA=", + "dev": true + }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -11736,12 +11837,6 @@ "minimatch": "3.0.4" }, "dependencies": { - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", - "dev": true - }, "commander": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", @@ -11754,15 +11849,15 @@ } }, "dmg-builder": { - "version": "22.11.3", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.11.3.tgz", - "integrity": "sha512-NGlorMQF2YGboVtHM8zP5EHxYhrxFGjtsnX6YCr9BV1bsjSPVyBJZpuxKnOOLj86zlYWYeiNGyj4NeUOLGgUCA==", + "version": "22.12.0", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.12.0.tgz", + "integrity": "sha512-5MANoNVctpiN536BLNDQp/gDk2BLRe23LE+RbOSt3I8b65V6mtvekjNiyUU5M+/UAbAzCcOZcCcaV3jDBuapaw==", "dev": true, "requires": { - "app-builder-lib": "22.11.3", - "builder-util": "22.11.3", - "builder-util-runtime": "8.7.5", - "dmg-license": "^1.0.8", + "app-builder-lib": "22.12.0", + "builder-util": "22.11.11", + "builder-util-runtime": "8.7.10", + "dmg-license": "^1.0.9", "fs-extra": "^10.0.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" @@ -11937,20 +12032,20 @@ } }, "electron-builder": { - "version": "22.11.3", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.11.3.tgz", - "integrity": "sha512-STv4uU3q00FzVgW9kMpRXSrhJxogzAZgIhFZl0mBZQC1VOAajNiEBsZPaU32jP23oxlgLQExj/ux6/frYk5vGA==", + "version": "22.12.0", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.12.0.tgz", + "integrity": "sha512-X6YA0R6oYsS2iy+u0w3Sdm7u9rTo4JggD/jabKG34nZ0Hs5/iPAHBkcVvXqiFdMvnywbh1jm/aaf4PWW6XNMHw==", "dev": true, "requires": { - "@types/yargs": "^16.0.1", - "app-builder-lib": "22.11.3", - "builder-util": "22.11.3", - "builder-util-runtime": "8.7.5", + "@types/yargs": "^17.0.1", + "app-builder-lib": "22.12.0", + "builder-util": "22.11.11", + "builder-util-runtime": "8.7.10", "chalk": "^4.1.1", - "dmg-builder": "22.11.3", + "dmg-builder": "22.12.0", "fs-extra": "^10.0.0", "is-ci": "^3.0.0", - "lazy-val": "^1.0.4", + "lazy-val": "^1.0.5", "read-config-file": "6.2.0", "update-notifier": "^5.1.0", "yargs": "^17.0.1" @@ -12121,19 +12216,59 @@ } } }, - "electron-publish": { - "version": "22.11.2", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.11.2.tgz", - "integrity": "sha512-RSrDyYL407QRryIN0QhQGJc5PjHK4gdCwTHYTH5Zl43753ZLVUMRmzW768H0Tb8hVM2VOymy8pNnQAHB5egoiQ==", + "electron-osx-sign": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.5.0.tgz", + "integrity": "sha512-icoRLHzFz/qxzDh/N4Pi2z4yVHurlsCAYQvsCSG7fCedJ4UJXBS6PoQyGH71IfcqKupcKeK7HX/NkyfG+v6vlQ==", "dev": true, "requires": { - "@types/fs-extra": "^9.0.7", - "builder-util": "22.11.2", - "builder-util-runtime": "8.7.4", - "chalk": "^4.1.0", - "fs-extra": "^9.1.0", - "lazy-val": "^1.0.4", - "mime": "^2.5.0" + "bluebird": "^3.5.0", + "compare-version": "^0.1.2", + "debug": "^2.6.8", + "isbinaryfile": "^3.0.2", + "minimist": "^1.2.0", + "plist": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "electron-publish": { + "version": "22.11.11", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.11.11.tgz", + "integrity": "sha512-XINI2yz7DpForvLDENr1zfi6yW+O3ufeIgNCg/nkqiD3tBM44AokgY3aYURzsi93ZwFscoQkR2LhmHDvn30oAw==", + "dev": true, + "requires": { + "@types/fs-extra": "^9.0.11", + "builder-util": "22.11.11", + "builder-util-runtime": "8.7.10", + "chalk": "^4.1.1", + "fs-extra": "^10.0.0", + "lazy-val": "^1.0.5", + "mime": "^2.5.2" }, "dependencies": { "ansi-styles": { @@ -12145,42 +12280,10 @@ "color-convert": "^2.0.1" } }, - "builder-util": { - "version": "22.11.2", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.11.2.tgz", - "integrity": "sha512-n5QkoRcNKy7KrBO8trpk7WRgdpBnOu68KVm+roSbDtZaW1qAmBplyThxnczcvjByVwD+UrsKd62eNIARiz2jyw==", - "dev": true, - "requires": { - "@types/debug": "^4.1.5", - "@types/fs-extra": "^9.0.7", - "7zip-bin": "~5.1.1", - "app-builder-bin": "3.5.13", - "bluebird-lst": "^1.0.9", - "builder-util-runtime": "8.7.4", - "chalk": "^4.1.0", - "debug": "^4.3.2", - "fs-extra": "^9.1.0", - "is-ci": "^3.0.0", - "js-yaml": "^4.0.0", - "source-map-support": "^0.5.19", - "stat-mode": "^1.0.0", - "temp-file": "^3.3.7" - } - }, - "builder-util-runtime": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.4.tgz", - "integrity": "sha512-2vDOwH0cyyCLQwW0Tsrg3RKKQpEcrV70KFun39E8RPzNFBOv9ds9juK8WUnO6ml+xJWKkKTjWLFdF3y+8GbPOw==", - "dev": true, - "requires": { - "debug": "^4.3.2", - "sax": "^1.2.4" - } - }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -12203,12 +12306,11 @@ "dev": true }, "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", "dev": true, "requires": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" @@ -14768,23 +14870,21 @@ } }, "plist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.2.tgz", - "integrity": "sha512-MSrkwZBdQ6YapHy87/8hDU8MnIcyxBKjeF+McXnr5A9MtffPewTs7G3hlpodT5TacyfIyFTaJEhh3GGcmasTgQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.3.tgz", + "integrity": "sha512-ghdOKN99hh1oEmAlwBmPYo4L+tSQ7O3jRpkhWqOrMz86CWotpVzMevvQ+czo7oPDpOZyA6K06Ci7QVHpoh9gaA==", "dev": true, - "optional": true, "requires": { "base64-js": "^1.5.1", "xmlbuilder": "^9.0.7", - "xmldom": "^0.5.0" + "xmldom": "^0.6.0" }, "dependencies": { "xmlbuilder": { "version": "9.0.7", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", - "dev": true, - "optional": true + "dev": true } } }, @@ -14800,6 +14900,12 @@ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "dev": true }, + "prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "dev": true + }, "pretty-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", @@ -15528,9 +15634,9 @@ } }, "smart-buffer": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", - "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true, "optional": true }, @@ -16181,9 +16287,9 @@ } }, "typescript": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz", - "integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", "dev": true }, "underscore": { @@ -17139,11 +17245,10 @@ "dev": true }, "xmldom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.5.0.tgz", - "integrity": "sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==", - "dev": true, - "optional": true + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.6.0.tgz", + "integrity": "sha512-iAcin401y58LckRZ0TkI4k0VSM1Qg0KGSc3i8rU+xrxe19A/BN1zHyVSJY7uoutVlaTSzYyk/v5AmkewAP7jtg==", + "dev": true }, "xtend": { "version": "4.0.2", diff --git a/package.json b/package.json index d029103..aa5e3a6 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "build": "webpack --config ./webpack.config.js", "electron": "electron ./dist/electron.js", "start": "npm run build && npm run electron", + "format": "prettier --write .", "package-win": "electron-builder -w appx:x64 && electron-builder -w appx:ia32 && electron-builder -w appx:arm64", "package-win-ci": "electron-builder -w --x64 -p never && electron-builder -w --ia32 -p never", "package-mac": "electron-builder --mac --x64", @@ -35,6 +36,7 @@ "js-md5": "^0.7.3", "lovefield": "^2.1.12", "nedb": "^1.8.0", + "prettier": "2.3.2", "qrcode.react": "^1.0.0", "react": "^16.13.1", "react-dom": "^16.13.1", @@ -45,7 +47,7 @@ "redux-thunk": "^2.3.0", "reselect": "^4.0.0", "ts-loader": "^7.0.4", - "typescript": "^3.9.2", + "typescript": "^4.3.5", "webpack": "^4.43.0", "webpack-cli": "^3.3.11" } diff --git a/src/bridges/settings.ts b/src/bridges/settings.ts index 3cc1640..0fbb636 100644 --- a/src/bridges/settings.ts +++ b/src/bridges/settings.ts @@ -1,4 +1,11 @@ -import { SourceGroup, ViewType, ThemeSettings, SearchEngines, ServiceConfigs, ViewConfigs } from "../schema-types" +import { + SourceGroup, + ViewType, + ThemeSettings, + SearchEngines, + ServiceConfigs, + ViewConfigs, +} from "../schema-types" import { ipcRenderer } from "electron" const settingsBridge = { @@ -114,15 +121,15 @@ const settingsBridge = { return ipcRenderer.sendSync("get-all-settings") as Object }, - setAll: (configs) => { + setAll: configs => { ipcRenderer.invoke("import-all-settings", configs) }, } -declare global { +declare global { interface Window { settings: typeof settingsBridge } } -export default settingsBridge \ No newline at end of file +export default settingsBridge diff --git a/src/bridges/utils.ts b/src/bridges/utils.ts index 16988af..35349bf 100644 --- a/src/bridges/utils.ts +++ b/src/bridges/utils.ts @@ -1,5 +1,9 @@ import { ipcRenderer } from "electron" -import { ImageCallbackTypes, TouchBarTexts, WindowStateListenerType } from "../schema-types" +import { + ImageCallbackTypes, + TouchBarTexts, + WindowStateListenerType, +} from "../schema-types" import { IObjectWithKey } from "@fluentui/react" const utilsBridge = { @@ -9,7 +13,7 @@ const utilsBridge = { return ipcRenderer.sendSync("get-version") }, - openExternal: (url: string, background=false) => { + openExternal: (url: string, background = false) => { ipcRenderer.invoke("open-external", url, background) }, @@ -17,12 +21,31 @@ const utilsBridge = { ipcRenderer.invoke("show-error-box", title, content) }, - showMessageBox: async (title: string, message: string, confirm: string, cancel: string, defaultCancel=false, type="none") => { - return await ipcRenderer.invoke("show-message-box", title, message, confirm, cancel, defaultCancel, type) as boolean + showMessageBox: async ( + title: string, + message: string, + confirm: string, + cancel: string, + defaultCancel = false, + type = "none" + ) => { + return (await ipcRenderer.invoke( + "show-message-box", + title, + message, + confirm, + cancel, + defaultCancel, + type + )) as boolean }, showSaveDialog: async (filters: Electron.FileFilter[], path: string) => { - let result = await ipcRenderer.invoke("show-save-dialog", filters, path) as boolean + let result = (await ipcRenderer.invoke( + "show-save-dialog", + filters, + path + )) as boolean if (result) { return (result: string, errmsg: string) => { ipcRenderer.invoke("write-save-result", result, errmsg) @@ -33,7 +56,7 @@ const utilsBridge = { }, showOpenDialog: async (filters: Electron.FileFilter[]) => { - return await ipcRenderer.invoke("show-open-dialog", filters) as string + return (await ipcRenderer.invoke("show-open-dialog", filters)) as string }, getCacheSize: async (): Promise => { @@ -44,13 +67,17 @@ const utilsBridge = { await ipcRenderer.invoke("clear-cache") }, - addMainContextListener: (callback: (pos: [number, number], text: string) => any) => { + addMainContextListener: ( + callback: (pos: [number, number], text: string) => any + ) => { ipcRenderer.removeAllListeners("window-context-menu") ipcRenderer.on("window-context-menu", (_, pos, text) => { callback(pos, text) }) }, - addWebviewContextListener: (callback: (pos: [number, number], text: string, url: string) => any) => { + addWebviewContextListener: ( + callback: (pos: [number, number], text: string, url: string) => any + ) => { ipcRenderer.removeAllListeners("webview-context-menu") ipcRenderer.on("webview-context-menu", (_, pos, text, url) => { callback(pos, text, url) @@ -102,7 +129,9 @@ const utilsBridge = { requestAttention: () => { ipcRenderer.invoke("request-attention") }, - addWindowStateListener: (callback: (type: WindowStateListenerType, state: boolean) => any) => { + addWindowStateListener: ( + callback: (type: WindowStateListenerType, state: boolean) => any + ) => { ipcRenderer.removeAllListeners("maximized") ipcRenderer.on("maximized", () => { callback(WindowStateListenerType.Maximized, true) @@ -132,7 +161,7 @@ const utilsBridge = { addTouchBarEventsListener: (callback: (IObjectWithKey) => any) => { ipcRenderer.removeAllListeners("touchbar-event") ipcRenderer.on("touchbar-event", (_, key: string) => { - callback({ key: key } ) + callback({ key: key }) }) }, initTouchBar: (texts: TouchBarTexts) => { @@ -143,10 +172,10 @@ const utilsBridge = { }, } -declare global { +declare global { interface Window { utils: typeof utilsBridge } } -export default utilsBridge \ No newline at end of file +export default utilsBridge diff --git a/src/components/article.tsx b/src/components/article.tsx index 42bafe3..74f869e 100644 --- a/src/components/article.tsx +++ b/src/components/article.tsx @@ -2,7 +2,16 @@ import * as React from "react" import intl from "react-intl-universal" import { renderToString } from "react-dom/server" import { RSSItem } from "../scripts/models/item" -import { Stack, CommandBarButton, IContextualMenuProps, FocusZone, ContextualMenuItemType, Spinner, Icon, Link } from "@fluentui/react" +import { + Stack, + CommandBarButton, + IContextualMenuProps, + FocusZone, + ContextualMenuItemType, + Spinner, + Icon, + Link, +} from "@fluentui/react" import { RSSSource, SourceOpenTarget } from "../scripts/models/source" import { shareSubmenu } from "./context-menu" import { platformCtrl, decodeFetchResponse } from "../scripts/utils" @@ -51,7 +60,8 @@ class Article extends React.Component { window.utils.addWebviewContextListener(this.contextMenuHandler) window.utils.addWebviewKeydownListener(this.keyDownHandler) window.utils.addWebviewErrorListener(this.webviewError) - if (props.source.openTarget === SourceOpenTarget.FullContent) this.loadFull() + if (props.source.openTarget === SourceOpenTarget.FullContent) + this.loadFull() } getFontSize = () => { @@ -59,7 +69,7 @@ class Article extends React.Component { } setFontSize = (size: number) => { window.settings.setFontSize(size) - this.setState({fontSize: size}) + this.setState({ fontSize: size }) } fontMenuProps = (): IContextualMenuProps => ({ @@ -68,8 +78,8 @@ class Article extends React.Component { text: String(size), canCheck: true, checked: size === this.state.fontSize, - onClick: () => this.setFontSize(size) - })) + onClick: () => this.setFontSize(size), + })), }) moreMenuProps = (): IContextualMenuProps => ({ @@ -78,33 +88,46 @@ class Article extends React.Component { key: "openInBrowser", text: intl.get("openExternal"), iconProps: { iconName: "NavigateExternalInline" }, - onClick: e => { window.utils.openExternal(this.props.item.link, platformCtrl(e)) } + onClick: e => { + window.utils.openExternal( + this.props.item.link, + platformCtrl(e) + ) + }, }, { key: "copyURL", text: intl.get("context.copyURL"), iconProps: { iconName: "Link" }, - onClick: () => { window.utils.writeClipboard(this.props.item.link) } + onClick: () => { + window.utils.writeClipboard(this.props.item.link) + }, }, { key: "toggleHidden", - text: this.props.item.hidden ? intl.get("article.unhide") : intl.get("article.hide"), - iconProps: { iconName: this.props.item.hidden ? "View" : "Hide3" }, - onClick: () => { this.props.toggleHidden(this.props.item) } + text: this.props.item.hidden + ? intl.get("article.unhide") + : intl.get("article.hide"), + iconProps: { + iconName: this.props.item.hidden ? "View" : "Hide3", + }, + onClick: () => { + this.props.toggleHidden(this.props.item) + }, }, { key: "fontMenu", text: intl.get("article.fontSize"), iconProps: { iconName: "FontSize" }, disabled: this.state.loadWebpage, - subMenuProps: this.fontMenuProps() + subMenuProps: this.fontMenuProps(), }, { key: "divider_1", itemType: ContextualMenuItemType.Divider, }, - ...shareSubmenu(this.props.item) - ] + ...shareSubmenu(this.props.item), + ], }) contextMenuHandler = (pos: [number, number], text: string, url: string) => { @@ -126,13 +149,16 @@ class Article extends React.Component { case "ArrowRight": this.props.offsetItem(input.key === "ArrowLeft" ? -1 : 1) break - case "l": case "L": + case "l": + case "L": this.toggleWebpage() break - case "w": case "W": + case "w": + case "W": this.toggleFull() break - case "H": case "h": + case "H": + case "h": if (!input.meta) this.props.toggleHidden(this.props.item) break default: @@ -144,7 +170,7 @@ class Article extends React.Component { ctrlKey: input.control, metaKey: input.meta, repeat: input.isAutoRepeat, - bubbles: true + bubbles: true, }) this.props.shortcuts(this.props.item, keyboardEvent) document.dispatchEvent(keyboardEvent) @@ -154,14 +180,14 @@ class Article extends React.Component { } webviewLoaded = () => { - this.setState({loaded: true}) + this.setState({ loaded: true }) } webviewError = (reason: string) => { - this.setState({error: true, errorDescription: reason}) + this.setState({ error: true, errorDescription: reason }) } webviewReload = () => { if (this.webview) { - this.setState({loaded: false, error: false}) + this.setState({ loaded: false, error: false }) this.webview.reload() } else if (this.state.loadFull) { this.loadFull() @@ -174,9 +200,11 @@ class Article extends React.Component { this.webview = webview if (webview) { webview.focus() - this.setState({loaded: false, error: false}) + this.setState({ loaded: false, error: false }) webview.addEventListener("did-stop-loading", this.webviewLoaded) - let card = document.querySelector(`#refocus div[data-iid="${this.props.item._id}"]`) as HTMLElement + let card = document.querySelector( + `#refocus div[data-iid="${this.props.item._id}"]` + ) as HTMLElement // @ts-ignore if (card) card.scrollIntoViewIfNeeded() } @@ -185,23 +213,32 @@ class Article extends React.Component { componentDidUpdate = (prevProps: ArticleProps) => { if (prevProps.item._id != this.props.item._id) { this.setState({ - loadWebpage: this.props.source.openTarget === SourceOpenTarget.Webpage, - loadFull: this.props.source.openTarget === SourceOpenTarget.FullContent, + loadWebpage: + this.props.source.openTarget === SourceOpenTarget.Webpage, + loadFull: + this.props.source.openTarget === + SourceOpenTarget.FullContent, }) - if (this.props.source.openTarget === SourceOpenTarget.FullContent) this.loadFull() + if (this.props.source.openTarget === SourceOpenTarget.FullContent) + this.loadFull() } this.componentDidMount() } componentWillUnmount = () => { - let refocus = document.querySelector(`#refocus div[data-iid="${this.props.item._id}"]`) as HTMLElement + let refocus = document.querySelector( + `#refocus div[data-iid="${this.props.item._id}"]` + ) as HTMLElement if (refocus) refocus.focus() } toggleWebpage = () => { if (this.state.loadWebpage) { this.setState({ loadWebpage: false }) - } else if (this.props.item.link.startsWith("https://") || this.props.item.link.startsWith("http://")) { + } else if ( + this.props.item.link.startsWith("https://") || + this.props.item.link.startsWith("http://") + ) { this.setState({ loadWebpage: true, loadFull: false }) } } @@ -209,7 +246,10 @@ class Article extends React.Component { toggleFull = () => { if (this.state.loadFull) { this.setState({ loadFull: false }) - } else if (this.props.item.link.startsWith("https://") || this.props.item.link.startsWith("http://")) { + } else if ( + this.props.item.link.startsWith("https://") || + this.props.item.link.startsWith("http://") + ) { this.setState({ loadFull: true, loadWebpage: false }) this.loadFull() } @@ -222,86 +262,173 @@ class Article extends React.Component { const html = await decodeFetchResponse(result, true) this.setState({ fullContent: html }) } catch { - this.setState({ loaded: true, error: true, errorDescription: "MERCURY_PARSER_FAILURE" }) + this.setState({ + loaded: true, + error: true, + errorDescription: "MERCURY_PARSER_FAILURE", + }) } } articleView = () => { - const a = encodeURIComponent(this.state.loadFull ? this.state.fullContent : this.props.item.content) - const h = encodeURIComponent(renderToString(<> -

{this.props.item.title}

-

{this.props.item.date.toLocaleString(this.props.locale, {hour12: !this.props.locale.startsWith("zh")})}

-
- )) - return `article/article.html?a=${a}&h=${h}&s=${this.state.fontSize}&u=${this.props.item.link}&m=${this.state.loadFull?1:0}` + const a = encodeURIComponent( + this.state.loadFull + ? this.state.fullContent + : this.props.item.content + ) + const h = encodeURIComponent( + renderToString( + <> +

{this.props.item.title}

+

+ {this.props.item.date.toLocaleString( + this.props.locale, + { hour12: !this.props.locale.startsWith("zh") } + )} +

+
+ + ) + ) + return `article/article.html?a=${a}&h=${h}&s=${this.state.fontSize}&u=${ + this.props.item.link + }&m=${this.state.loadFull ? 1 : 0}` } render = () => ( - - - + + + - {this.state.loaded - ? (this.props.source.iconurl && ) - : } + {this.state.loaded ? ( + this.props.source.iconurl && ( + + ) + ) : ( + + )} {this.props.source.name} - {this.props.item.creator && {this.props.item.creator}} + {this.props.item.creator && ( + + {this.props.item.creator} + + )} this.props.toggleHasRead(this.props.item)} /> + title={ + this.props.item.hasRead + ? intl.get("article.markUnread") + : intl.get("article.markRead") + } + iconProps={ + this.props.item.hasRead + ? { iconName: "StatusCircleRing" } + : { + iconName: "RadioBtnOn", + style: { + fontSize: 14, + textAlign: "center", + }, + } + } + onClick={() => + this.props.toggleHasRead(this.props.item) + } + /> this.props.toggleStarred(this.props.item)} /> + title={ + this.props.item.starred + ? intl.get("article.unstar") + : intl.get("article.star") + } + iconProps={{ + iconName: this.props.item.starred + ? "FavoriteStarFill" + : "FavoriteStar", + }} + onClick={() => + this.props.toggleStarred(this.props.item) + } + /> + iconProps={{ iconName: "RawSource" }} + onClick={this.toggleFull} + /> + iconProps={{ iconName: "Globe" }} + onClick={this.toggleWebpage} + /> + iconProps={{ iconName: "More" }} + menuIconProps={{ style: { display: "none" } }} + menuProps={this.moreMenuProps()} + /> - + + iconProps={{ iconName: "BackToWindow" }} + onClick={this.props.dismiss} + /> - {(!this.state.loadFull || this.state.fullContent) && } + {(!this.state.loadFull || this.state.fullContent) && ( + + )} {this.state.error && ( - - - + + + {intl.get("article.error")} - {intl.get("article.reload")} + + + {intl.get("article.reload")} + + - {this.state.errorDescription} + + {this.state.errorDescription} + )} ) } -export default Article \ No newline at end of file +export default Article diff --git a/src/components/cards/card.tsx b/src/components/cards/card.tsx index bde1b4a..43e335b 100644 --- a/src/components/cards/card.tsx +++ b/src/components/cards/card.tsx @@ -61,4 +61,4 @@ export namespace Card { const onKeyDown = (props: Props, e: React.KeyboardEvent) => { props.shortcuts(props.item, e.nativeEvent) } -} \ No newline at end of file +} diff --git a/src/components/cards/compact-card.tsx b/src/components/cards/compact-card.tsx index 7128806..566bfdc 100644 --- a/src/components/cards/compact-card.tsx +++ b/src/components/cards/compact-card.tsx @@ -10,7 +10,7 @@ const className = (props: Card.Props) => { return cn.join(" ") } -const CompactCard: React.FunctionComponent = (props) => ( +const CompactCard: React.FunctionComponent = props => (
= (props) => ( data-is-focusable>
- - + + + + + +
) -export default CompactCard \ No newline at end of file +export default CompactCard diff --git a/src/components/cards/default-card.tsx b/src/components/cards/default-card.tsx index 55410cb..c4d08a8 100644 --- a/src/components/cards/default-card.tsx +++ b/src/components/cards/default-card.tsx @@ -10,7 +10,7 @@ const className = (props: Card.Props) => { return cn.join(" ") } -const DefaultCard: React.FunctionComponent = (props) => ( +const DefaultCard: React.FunctionComponent = props => (
= (props) => ( ) : null} -

+

+ +

) -export default DefaultCard \ No newline at end of file +export default DefaultCard diff --git a/src/components/cards/highlights.tsx b/src/components/cards/highlights.tsx index 90bd239..e790519 100644 --- a/src/components/cards/highlights.tsx +++ b/src/components/cards/highlights.tsx @@ -8,11 +8,14 @@ type HighlightsProps = { title?: boolean } -const Highlights: React.FunctionComponent = (props) => { +const Highlights: React.FunctionComponent = props => { const spans: [string, boolean][] = new Array() - const flags = (props.filter.type & FilterType.CaseInsensitive) ? "ig" : "g" + const flags = props.filter.type & FilterType.CaseInsensitive ? "ig" : "g" let regex: RegExp - if (props.filter.search === "" || !(regex = validateRegex(props.filter.search, flags))) { + if ( + props.filter.search === "" || + !(regex = validateRegex(props.filter.search, flags)) + ) { if (props.title) spans.push([props.text, false]) else spans.push([props.text.substr(0, 325), false]) } else if (props.title) { @@ -22,7 +25,10 @@ const Highlights: React.FunctionComponent = (props) => { match = regex.exec(props.text) if (match) { if (startIndex != match.index) { - spans.push([props.text.substring(startIndex, match.index), false]) + spans.push([ + props.text.substring(startIndex, match.index), + false, + ]) } spans.push([match[0], true]) } else { @@ -33,8 +39,14 @@ const Highlights: React.FunctionComponent = (props) => { const match = regex.exec(props.text) if (match) { if (match.index != 0) { - const startIndex = Math.max(match.index - 25, props.text.lastIndexOf(" ", Math.max(match.index - 10, 0))) - spans.push([props.text.substring(Math.max(0, startIndex), match.index), false]) + const startIndex = Math.max( + match.index - 25, + props.text.lastIndexOf(" ", Math.max(match.index - 10, 0)) + ) + spans.push([ + props.text.substring(Math.max(0, startIndex), match.index), + false, + ]) } spans.push([match[0], true]) if (regex.lastIndex < props.text.length) { @@ -45,9 +57,13 @@ const Highlights: React.FunctionComponent = (props) => { } } - return <> - {spans.map(([text, flag]) => flag ? {text} : text)} - + return ( + <> + {spans.map(([text, flag]) => + flag ? {text} : text + )} + + ) } -export default Highlights \ No newline at end of file +export default Highlights diff --git a/src/components/cards/info.tsx b/src/components/cards/info.tsx index c71a264..8899a12 100644 --- a/src/components/cards/info.tsx +++ b/src/components/cards/info.tsx @@ -10,7 +10,7 @@ type CardInfoProps = { showCreator?: boolean } -const CardInfo: React.FunctionComponent = (props) => ( +const CardInfo: React.FunctionComponent = props => (

{props.source.iconurl ? : null} @@ -19,10 +19,12 @@ const CardInfo: React.FunctionComponent = (props) => ( {props.item.creator} )} - {props.item.starred ? : null} + {props.item.starred ? ( + + ) : null} {props.item.hasRead ? null : } {props.hideTime ? null :

) -export default CardInfo \ No newline at end of file +export default CardInfo diff --git a/src/components/cards/list-card.tsx b/src/components/cards/list-card.tsx index 156ecbc..5afa8e1 100644 --- a/src/components/cards/list-card.tsx +++ b/src/components/cards/list-card.tsx @@ -8,27 +8,41 @@ const className = (props: Card.Props) => { let cn = ["card", "list-card"] if (props.item.hidden) cn.push("hidden") if (props.selected) cn.push("selected") - if ((props.viewConfigs & ViewConfigs.FadeRead) && props.item.hasRead) cn.push("read") + if (props.viewConfigs & ViewConfigs.FadeRead && props.item.hasRead) + cn.push("read") return cn.join(" ") } -const ListCard: React.FunctionComponent = (props) => ( +const ListCard: React.FunctionComponent = props => (
- {props.item.thumb && (props.viewConfigs & ViewConfigs.ShowCover) ? ( -
+ {props.item.thumb && props.viewConfigs & ViewConfigs.ShowCover ? ( +
+ +
) : null}
-

+

+ +

{Boolean(props.viewConfigs & ViewConfigs.ShowSnippet) && ( -

+

+ +

)}
) -export default ListCard \ No newline at end of file +export default ListCard diff --git a/src/components/cards/magazine-card.tsx b/src/components/cards/magazine-card.tsx index 1a170f8..d38f675 100644 --- a/src/components/cards/magazine-card.tsx +++ b/src/components/cards/magazine-card.tsx @@ -10,23 +10,36 @@ const className = (props: Card.Props) => { return cn.join(" ") } -const MagazineCard: React.FunctionComponent = (props) => ( +const MagazineCard: React.FunctionComponent = props => (
{props.item.thumb ? ( -
+
+ +
) : null}
-

-

+

+ +

+

+ +

) -export default MagazineCard \ No newline at end of file +export default MagazineCard diff --git a/src/components/context-menu.tsx b/src/components/context-menu.tsx index 80376bd..e005855 100644 --- a/src/components/context-menu.tsx +++ b/src/components/context-menu.tsx @@ -1,8 +1,18 @@ import * as React from "react" import intl from "react-intl-universal" import QRCode from "qrcode.react" -import { cutText, webSearch, getSearchEngineName, platformCtrl } from "../scripts/utils" -import { ContextualMenu, IContextualMenuItem, ContextualMenuItemType, DirectionalHint } from "office-ui-fabric-react/lib/ContextualMenu" +import { + cutText, + webSearch, + getSearchEngineName, + platformCtrl, +} from "../scripts/utils" +import { + ContextualMenu, + IContextualMenuItem, + ContextualMenuItemType, + DirectionalHint, +} from "office-ui-fabric-react/lib/ContextualMenu" import { ContextMenuType } from "../scripts/models/app" import { RSSItem } from "../scripts/models/item" import { ContextReduxProps } from "../containers/context-menu-container" @@ -37,15 +47,12 @@ export type ContextMenuProps = ContextReduxProps & { } export const shareSubmenu = (item: RSSItem): IContextualMenuItem[] => [ - { key: "qr", url: item.link, onRender: renderShareQR } + { key: "qr", url: item.link, onRender: renderShareQR }, ] export const renderShareQR = (item: IContextualMenuItem) => (
- +
) @@ -55,143 +62,222 @@ function getSearchItem(text: string): IContextualMenuItem { key: "searchText", text: intl.get("context.search", { text: cutText(text, 15), - engine: getSearchEngineName(engine) + engine: getSearchEngineName(engine), }), iconProps: { iconName: "Search" }, - onClick: () => webSearch(text, engine) + onClick: () => webSearch(text, engine), } } export class ContextMenu extends React.Component { getItems = (): IContextualMenuItem[] => { switch (this.props.type) { - case ContextMenuType.Item: return [ - { - key: "showItem", - text: intl.get("context.read"), - iconProps: { iconName: "TextDocument" }, - onClick: () => { - this.props.markRead(this.props.item) - this.props.showItem(this.props.feedId, this.props.item) - } - }, - { - key: "openInBrowser", - text: intl.get("openExternal"), - iconProps: { iconName: "NavigateExternalInline" }, - onClick: (e) => { - this.props.markRead(this.props.item) - window.utils.openExternal(this.props.item.link, platformCtrl(e)) - } - }, - { - key: "markAsRead", - text: this.props.item.hasRead ? intl.get("article.markUnread") : intl.get("article.markRead"), - iconProps: this.props.item.hasRead - ? { iconName: "RadioBtnOn", style: { fontSize: 14, textAlign: "center" } } - : { iconName: "StatusCircleRing" }, - onClick: () => { - if (this.props.item.hasRead) this.props.markUnread(this.props.item) - else this.props.markRead(this.props.item) - }, - split: true, - subMenuProps: { - items: [ - { - key: "markBelow", - text: intl.get("article.markBelow"), - iconProps: { iconName: "Down", style: { fontSize: 14 } }, - onClick: () => this.props.markAllRead(null, this.props.item.date) - }, - { - key: "markAbove", - text: intl.get("article.markAbove"), - iconProps: { iconName: "Up", style: { fontSize: 14 } }, - onClick: () => this.props.markAllRead(null, this.props.item.date, false) - } - ] - } - }, - { - key: "toggleStarred", - text: this.props.item.starred ? intl.get("article.unstar") : intl.get("article.star"), - iconProps: { iconName: this.props.item.starred ? "FavoriteStar" : "FavoriteStarFill" }, - onClick: () => { this.props.toggleStarred(this.props.item) } - }, - { - key: "toggleHidden", - text: this.props.item.hidden ? intl.get("article.unhide") : intl.get("article.hide"), - iconProps: { iconName: this.props.item.hidden ? "View" : "Hide3" }, - onClick: () => { this.props.toggleHidden(this.props.item) } - }, - { - key: "divider_1", - itemType: ContextualMenuItemType.Divider, - }, - { - key: "share", - text: intl.get("context.share"), - iconProps: { iconName: "Share" }, - subMenuProps: { - items: shareSubmenu(this.props.item) - } - }, - { - key: "copyTitle", - text: intl.get("context.copyTitle"), - onClick: () => { window.utils.writeClipboard(this.props.item.title) } - }, - { - key: "copyURL", - text: intl.get("context.copyURL"), - onClick: () => { window.utils.writeClipboard(this.props.item.link) } - }, - ...(this.props.viewConfigs !== undefined ? [ + case ContextMenuType.Item: + return [ { - key: "divider_2", - itemType: ContextualMenuItemType.Divider, + key: "showItem", + text: intl.get("context.read"), + iconProps: { iconName: "TextDocument" }, + onClick: () => { + this.props.markRead(this.props.item) + this.props.showItem( + this.props.feedId, + this.props.item + ) + }, }, { - key: "view", - text: intl.get("context.view"), + key: "openInBrowser", + text: intl.get("openExternal"), + iconProps: { iconName: "NavigateExternalInline" }, + onClick: e => { + this.props.markRead(this.props.item) + window.utils.openExternal( + this.props.item.link, + platformCtrl(e) + ) + }, + }, + { + key: "markAsRead", + text: this.props.item.hasRead + ? intl.get("article.markUnread") + : intl.get("article.markRead"), + iconProps: this.props.item.hasRead + ? { + iconName: "RadioBtnOn", + style: { fontSize: 14, textAlign: "center" }, + } + : { iconName: "StatusCircleRing" }, + onClick: () => { + if (this.props.item.hasRead) + this.props.markUnread(this.props.item) + else this.props.markRead(this.props.item) + }, + split: true, subMenuProps: { items: [ { - key: "showCover", - text: intl.get("context.showCover"), - canCheck: true, - checked: Boolean(this.props.viewConfigs & ViewConfigs.ShowCover), - onClick: () => this.props.setViewConfigs(this.props.viewConfigs ^ ViewConfigs.ShowCover) + key: "markBelow", + text: intl.get("article.markBelow"), + iconProps: { + iconName: "Down", + style: { fontSize: 14 }, + }, + onClick: () => + this.props.markAllRead( + null, + this.props.item.date + ), }, { - key: "showSnippet", - text: intl.get("context.showSnippet"), - canCheck: true, - checked: Boolean(this.props.viewConfigs & ViewConfigs.ShowSnippet), - onClick: () => this.props.setViewConfigs(this.props.viewConfigs ^ ViewConfigs.ShowSnippet) + key: "markAbove", + text: intl.get("article.markAbove"), + iconProps: { + iconName: "Up", + style: { fontSize: 14 }, + }, + onClick: () => + this.props.markAllRead( + null, + this.props.item.date, + false + ), }, - { - key: "fadeRead", - text: intl.get("context.fadeRead"), - canCheck: true, - checked: Boolean(this.props.viewConfigs & ViewConfigs.FadeRead), - onClick: () => this.props.setViewConfigs(this.props.viewConfigs ^ ViewConfigs.FadeRead) - } - ] - } + ], + }, }, - ] : []) - ] - case ContextMenuType.Text: { - const items: IContextualMenuItem[] = this.props.text? [ { - key: "copyText", - text: intl.get("context.copy"), - iconProps: { iconName: "Copy" }, - onClick: () => { window.utils.writeClipboard(this.props.text) } + key: "toggleStarred", + text: this.props.item.starred + ? intl.get("article.unstar") + : intl.get("article.star"), + iconProps: { + iconName: this.props.item.starred + ? "FavoriteStar" + : "FavoriteStarFill", + }, + onClick: () => { + this.props.toggleStarred(this.props.item) + }, }, - getSearchItem(this.props.text) - ] : [] + { + key: "toggleHidden", + text: this.props.item.hidden + ? intl.get("article.unhide") + : intl.get("article.hide"), + iconProps: { + iconName: this.props.item.hidden ? "View" : "Hide3", + }, + onClick: () => { + this.props.toggleHidden(this.props.item) + }, + }, + { + key: "divider_1", + itemType: ContextualMenuItemType.Divider, + }, + { + key: "share", + text: intl.get("context.share"), + iconProps: { iconName: "Share" }, + subMenuProps: { + items: shareSubmenu(this.props.item), + }, + }, + { + key: "copyTitle", + text: intl.get("context.copyTitle"), + onClick: () => { + window.utils.writeClipboard(this.props.item.title) + }, + }, + { + key: "copyURL", + text: intl.get("context.copyURL"), + onClick: () => { + window.utils.writeClipboard(this.props.item.link) + }, + }, + ...(this.props.viewConfigs !== undefined + ? [ + { + key: "divider_2", + itemType: ContextualMenuItemType.Divider, + }, + { + key: "view", + text: intl.get("context.view"), + subMenuProps: { + items: [ + { + key: "showCover", + text: intl.get( + "context.showCover" + ), + canCheck: true, + checked: Boolean( + this.props.viewConfigs & + ViewConfigs.ShowCover + ), + onClick: () => + this.props.setViewConfigs( + this.props.viewConfigs ^ + ViewConfigs.ShowCover + ), + }, + { + key: "showSnippet", + text: intl.get( + "context.showSnippet" + ), + canCheck: true, + checked: Boolean( + this.props.viewConfigs & + ViewConfigs.ShowSnippet + ), + onClick: () => + this.props.setViewConfigs( + this.props.viewConfigs ^ + ViewConfigs.ShowSnippet + ), + }, + { + key: "fadeRead", + text: intl.get( + "context.fadeRead" + ), + canCheck: true, + checked: Boolean( + this.props.viewConfigs & + ViewConfigs.FadeRead + ), + onClick: () => + this.props.setViewConfigs( + this.props.viewConfigs ^ + ViewConfigs.FadeRead + ), + }, + ], + }, + }, + ] + : []), + ] + case ContextMenuType.Text: { + const items: IContextualMenuItem[] = this.props.text + ? [ + { + key: "copyText", + text: intl.get("context.copy"), + iconProps: { iconName: "Copy" }, + onClick: () => { + window.utils.writeClipboard(this.props.text) + }, + }, + getSearchItem(this.props.text), + ] + : [] if (this.props.url) { items.push({ key: "urlSection", @@ -202,229 +288,320 @@ export class ContextMenu extends React.Component { { key: "openInBrowser", text: intl.get("openExternal"), - iconProps: { iconName: "NavigateExternalInline" }, - onClick: (e) => { window.utils.openExternal(this.props.url, platformCtrl(e)) } + iconProps: { + iconName: "NavigateExternalInline", + }, + onClick: e => { + window.utils.openExternal( + this.props.url, + platformCtrl(e) + ) + }, }, { key: "copyURL", text: intl.get("context.copyURL"), iconProps: { iconName: "Link" }, - onClick: () => { window.utils.writeClipboard(this.props.url) } - } - ] - } + onClick: () => { + window.utils.writeClipboard( + this.props.url + ) + }, + }, + ], + }, }) } return items } - case ContextMenuType.Image: return [ - { - key: "openInBrowser", - text: intl.get("openExternal"), - iconProps: { iconName: "NavigateExternalInline" }, - onClick: (e) => { - if (platformCtrl(e)) { - window.utils.imageCallback(ImageCallbackTypes.OpenExternalBg) - } else { - window.utils.imageCallback(ImageCallbackTypes.OpenExternal) - } - } - }, - { - key: "saveImageAs", - text: intl.get("context.saveImageAs"), - iconProps: { iconName: "SaveTemplate" }, - onClick: () => { window.utils.imageCallback(ImageCallbackTypes.SaveAs) } - }, - { - key: "copyImage", - text: intl.get("context.copyImage"), - iconProps: { iconName: "FileImage" }, - onClick: () => { window.utils.imageCallback(ImageCallbackTypes.Copy) } - }, - { - key: "copyImageURL", - text: intl.get("context.copyImageURL"), - iconProps: { iconName: "Link" }, - onClick: () => { window.utils.imageCallback(ImageCallbackTypes.CopyLink) } - } - ] - case ContextMenuType.View: return [ - { - key: "section_1", - itemType: ContextualMenuItemType.Section, - sectionProps: { - title: intl.get("context.view"), - bottomDivider: true, - items: [ - { - key: "cardView", - text: intl.get("context.cardView"), - iconProps: { iconName: "GridViewMedium" }, - canCheck: true, - checked: this.props.viewType === ViewType.Cards, - onClick: () => this.props.switchView(ViewType.Cards) - }, - { - key: "listView", - text: intl.get("context.listView"), - iconProps: { iconName: "BacklogList" }, - canCheck: true, - checked: this.props.viewType === ViewType.List, - onClick: () => this.props.switchView(ViewType.List) - }, - { - key: "magazineView", - text: intl.get("context.magazineView"), - iconProps: { iconName: "Articles" }, - canCheck: true, - checked: this.props.viewType === ViewType.Magazine, - onClick: () => this.props.switchView(ViewType.Magazine) - }, - { - key: "compactView", - text: intl.get("context.compactView"), - iconProps: { iconName: "BulletedList" }, - canCheck: true, - checked: this.props.viewType === ViewType.Compact, - onClick: () => this.props.switchView(ViewType.Compact) - }, - ] - } - }, - { - key: "section_2", - itemType: ContextualMenuItemType.Section, - sectionProps: { - title: intl.get("context.filter"), - bottomDivider: true, - items: [ - { - key: "allArticles", - text: intl.get("allArticles"), - iconProps: { iconName: "ClearFilter" }, - canCheck: true, - checked: (this.props.filter & ~FilterType.Toggles) == FilterType.Default, - onClick: () => this.props.switchFilter(FilterType.Default) - }, - { - key: "unreadOnly", - text: intl.get("context.unreadOnly"), - iconProps: { iconName: "RadioBtnOn", style: { fontSize: 14, textAlign: "center" } }, - canCheck: true, - checked: (this.props.filter & ~FilterType.Toggles) == FilterType.UnreadOnly, - onClick: () => this.props.switchFilter(FilterType.UnreadOnly) - }, - { - key: "starredOnly", - text: intl.get("context.starredOnly"), - iconProps: { iconName: "FavoriteStarFill" }, - canCheck: true, - checked: (this.props.filter & ~FilterType.Toggles) == FilterType.StarredOnly, - onClick: () => this.props.switchFilter(FilterType.StarredOnly) + case ContextMenuType.Image: + return [ + { + key: "openInBrowser", + text: intl.get("openExternal"), + iconProps: { iconName: "NavigateExternalInline" }, + onClick: e => { + if (platformCtrl(e)) { + window.utils.imageCallback( + ImageCallbackTypes.OpenExternalBg + ) + } else { + window.utils.imageCallback( + ImageCallbackTypes.OpenExternal + ) } - ] - } - }, - { - key: "section_3", - itemType: ContextualMenuItemType.Section, - sectionProps: { - title: intl.get("search"), - bottomDivider: true, - items: [ - { - key: "caseSensitive", - text: intl.get("context.caseSensitive"), - iconProps: { style: { fontSize: 12, fontStyle: "normal" }, children: "Aa" }, - canCheck: true, - checked: !(this.props.filter & FilterType.CaseInsensitive), - onClick: () => this.props.toggleFilter(FilterType.CaseInsensitive) - }, - { - key: "fullSearch", - text: intl.get("context.fullSearch"), - iconProps: { iconName: "Breadcrumb" }, - canCheck: true, - checked: Boolean(this.props.filter & FilterType.FullSearch), - onClick: () => this.props.toggleFilter(FilterType.FullSearch) - }, - ] - } - }, - { - key: "showHidden", - text: intl.get("context.showHidden"), - canCheck: true, - checked: Boolean(this.props.filter & FilterType.ShowHidden), - onClick: () => this.props.toggleFilter(FilterType.ShowHidden) - } - ] - case ContextMenuType.Group: return [ - { - key: "markAllRead", - text: intl.get("nav.markAllRead"), - iconProps: { iconName: "CheckMark" }, - onClick: () => this.props.markAllRead(this.props.sids) - }, - { - key: "refresh", - text: intl.get("nav.refresh"), - iconProps: { iconName: "Sync" }, - onClick: () => this.props.fetchItems(this.props.sids) - }, - { - key: "manage", - text: intl.get("context.manageSources"), - iconProps: { iconName: "Settings" }, - onClick: () => this.props.settings(this.props.sids) - } - ] - case ContextMenuType.MarkRead: return [ - { - key: "section_1", - itemType: ContextualMenuItemType.Section, - sectionProps: { - title: intl.get("nav.markAllRead"), - items: [ - { - key: "all", - text: intl.get("allArticles"), - iconProps: { iconName: "ReceiptCheck" }, - onClick: () => this.props.markAllRead() - }, - { - key: "1d", - text: intl.get("app.daysAgo", { days: 1 }), - onClick: () => { - let date = new Date() - date.setTime(date.getTime() - 86400000) - this.props.markAllRead(null, date) - } - }, - { - key: "3d", - text: intl.get("app.daysAgo", { days: 3 }), - onClick: () => { - let date = new Date() - date.setTime(date.getTime() - 3 * 86400000) - this.props.markAllRead(null, date) - } - }, - { - key: "7d", - text: intl.get("app.daysAgo", { days: 7 }), - onClick: () => { - let date = new Date() - date.setTime(date.getTime() - 7 * 86400000) - this.props.markAllRead(null, date) - } - } - ] - } - } - ] - default: return [] + }, + }, + { + key: "saveImageAs", + text: intl.get("context.saveImageAs"), + iconProps: { iconName: "SaveTemplate" }, + onClick: () => { + window.utils.imageCallback( + ImageCallbackTypes.SaveAs + ) + }, + }, + { + key: "copyImage", + text: intl.get("context.copyImage"), + iconProps: { iconName: "FileImage" }, + onClick: () => { + window.utils.imageCallback(ImageCallbackTypes.Copy) + }, + }, + { + key: "copyImageURL", + text: intl.get("context.copyImageURL"), + iconProps: { iconName: "Link" }, + onClick: () => { + window.utils.imageCallback( + ImageCallbackTypes.CopyLink + ) + }, + }, + ] + case ContextMenuType.View: + return [ + { + key: "section_1", + itemType: ContextualMenuItemType.Section, + sectionProps: { + title: intl.get("context.view"), + bottomDivider: true, + items: [ + { + key: "cardView", + text: intl.get("context.cardView"), + iconProps: { iconName: "GridViewMedium" }, + canCheck: true, + checked: + this.props.viewType === ViewType.Cards, + onClick: () => + this.props.switchView(ViewType.Cards), + }, + { + key: "listView", + text: intl.get("context.listView"), + iconProps: { iconName: "BacklogList" }, + canCheck: true, + checked: + this.props.viewType === ViewType.List, + onClick: () => + this.props.switchView(ViewType.List), + }, + { + key: "magazineView", + text: intl.get("context.magazineView"), + iconProps: { iconName: "Articles" }, + canCheck: true, + checked: + this.props.viewType === + ViewType.Magazine, + onClick: () => + this.props.switchView( + ViewType.Magazine + ), + }, + { + key: "compactView", + text: intl.get("context.compactView"), + iconProps: { iconName: "BulletedList" }, + canCheck: true, + checked: + this.props.viewType === + ViewType.Compact, + onClick: () => + this.props.switchView(ViewType.Compact), + }, + ], + }, + }, + { + key: "section_2", + itemType: ContextualMenuItemType.Section, + sectionProps: { + title: intl.get("context.filter"), + bottomDivider: true, + items: [ + { + key: "allArticles", + text: intl.get("allArticles"), + iconProps: { iconName: "ClearFilter" }, + canCheck: true, + checked: + (this.props.filter & + ~FilterType.Toggles) == + FilterType.Default, + onClick: () => + this.props.switchFilter( + FilterType.Default + ), + }, + { + key: "unreadOnly", + text: intl.get("context.unreadOnly"), + iconProps: { + iconName: "RadioBtnOn", + style: { + fontSize: 14, + textAlign: "center", + }, + }, + canCheck: true, + checked: + (this.props.filter & + ~FilterType.Toggles) == + FilterType.UnreadOnly, + onClick: () => + this.props.switchFilter( + FilterType.UnreadOnly + ), + }, + { + key: "starredOnly", + text: intl.get("context.starredOnly"), + iconProps: { iconName: "FavoriteStarFill" }, + canCheck: true, + checked: + (this.props.filter & + ~FilterType.Toggles) == + FilterType.StarredOnly, + onClick: () => + this.props.switchFilter( + FilterType.StarredOnly + ), + }, + ], + }, + }, + { + key: "section_3", + itemType: ContextualMenuItemType.Section, + sectionProps: { + title: intl.get("search"), + bottomDivider: true, + items: [ + { + key: "caseSensitive", + text: intl.get("context.caseSensitive"), + iconProps: { + style: { + fontSize: 12, + fontStyle: "normal", + }, + children: "Aa", + }, + canCheck: true, + checked: !( + this.props.filter & + FilterType.CaseInsensitive + ), + onClick: () => + this.props.toggleFilter( + FilterType.CaseInsensitive + ), + }, + { + key: "fullSearch", + text: intl.get("context.fullSearch"), + iconProps: { iconName: "Breadcrumb" }, + canCheck: true, + checked: Boolean( + this.props.filter & + FilterType.FullSearch + ), + onClick: () => + this.props.toggleFilter( + FilterType.FullSearch + ), + }, + ], + }, + }, + { + key: "showHidden", + text: intl.get("context.showHidden"), + canCheck: true, + checked: Boolean( + this.props.filter & FilterType.ShowHidden + ), + onClick: () => + this.props.toggleFilter(FilterType.ShowHidden), + }, + ] + case ContextMenuType.Group: + return [ + { + key: "markAllRead", + text: intl.get("nav.markAllRead"), + iconProps: { iconName: "CheckMark" }, + onClick: () => this.props.markAllRead(this.props.sids), + }, + { + key: "refresh", + text: intl.get("nav.refresh"), + iconProps: { iconName: "Sync" }, + onClick: () => this.props.fetchItems(this.props.sids), + }, + { + key: "manage", + text: intl.get("context.manageSources"), + iconProps: { iconName: "Settings" }, + onClick: () => this.props.settings(this.props.sids), + }, + ] + case ContextMenuType.MarkRead: + return [ + { + key: "section_1", + itemType: ContextualMenuItemType.Section, + sectionProps: { + title: intl.get("nav.markAllRead"), + items: [ + { + key: "all", + text: intl.get("allArticles"), + iconProps: { iconName: "ReceiptCheck" }, + onClick: () => this.props.markAllRead(), + }, + { + key: "1d", + text: intl.get("app.daysAgo", { days: 1 }), + onClick: () => { + let date = new Date() + date.setTime(date.getTime() - 86400000) + this.props.markAllRead(null, date) + }, + }, + { + key: "3d", + text: intl.get("app.daysAgo", { days: 3 }), + onClick: () => { + let date = new Date() + date.setTime( + date.getTime() - 3 * 86400000 + ) + this.props.markAllRead(null, date) + }, + }, + { + key: "7d", + text: intl.get("app.daysAgo", { days: 7 }), + onClick: () => { + let date = new Date() + date.setTime( + date.getTime() - 7 * 86400000 + ) + this.props.markAllRead(null, date) + }, + }, + ], + }, + }, + ] + default: + return [] } } @@ -432,9 +609,16 @@ export class ContextMenu extends React.Component { return this.props.type == ContextMenuType.Hidden ? null : ( + items={this.getItems()} + target={ + this.props.event || + (this.props.position && { + left: this.props.position[0], + top: this.props.position[1], + }) + } + onDismiss={this.props.close} + /> ) } -} \ No newline at end of file +} diff --git a/src/components/feeds/cards-feed.tsx b/src/components/feeds/cards-feed.tsx index 3cfb2b4..9e9241f 100644 --- a/src/components/feeds/cards-feed.tsx +++ b/src/components/feeds/cards-feed.tsx @@ -2,9 +2,9 @@ import * as React from "react" import intl from "react-intl-universal" import { FeedProps } from "./feed" import DefaultCard from "../cards/default-card" -import { PrimaryButton, FocusZone } from 'office-ui-fabric-react'; -import { RSSItem } from "../../scripts/models/item"; -import { List, AnimationClassNames } from "@fluentui/react"; +import { PrimaryButton, FocusZone } from "office-ui-fabric-react" +import { RSSItem } from "../../scripts/models/item" +import { List, AnimationClassNames } from "@fluentui/react" class CardsFeed extends React.Component { observer: ResizeObserver @@ -12,12 +12,17 @@ class CardsFeed extends React.Component { updateWindowSize = (entries: ResizeObserverEntry[]) => { if (entries) { - this.setState({ width: entries[0].contentRect.width - 40, height: window.innerHeight }) + this.setState({ + width: entries[0].contentRect.width - 40, + height: window.innerHeight, + }) } - }; + } componentDidMount() { - this.setState({ width: document.querySelector(".main").clientWidth - 40 }) + this.setState({ + width: document.querySelector(".main").clientWidth - 40, + }) this.observer = new ResizeObserver(this.updateWindowSize) this.observer.observe(document.querySelector(".main")) } @@ -31,33 +36,39 @@ class CardsFeed extends React.Component { return elemPerRow * rows } getPageHeight = () => { - return this.state.height + (304 - this.state.height % 304) + return this.state.height + (304 - (this.state.height % 304)) } flexFixItems = () => { let elemPerRow = Math.floor(this.state.width / 280) let elemLastRow = this.props.items.length % elemPerRow - let items = [ ...this.props.items ] - for (let i = 0; i < (elemPerRow - elemLastRow); i += 1) items.push(null) + let items = [...this.props.items] + for (let i = 0; i < elemPerRow - elemLastRow; i += 1) items.push(null) return items } - onRenderItem = (item: RSSItem, index: number) => item ? ( - - ) : (
) + onRenderItem = (item: RSSItem, index: number) => + item ? ( + + ) : ( +
+ ) canFocusChild = (el: HTMLElement) => { if (el.id === "load-more") { const container = document.getElementById("refocus") - const result = container.scrollTop > container.scrollHeight - 2 * container.offsetHeight + const result = + container.scrollTop > + container.scrollHeight - 2 * container.offsetHeight if (!result) container.scrollTop += 100 return result } else { @@ -66,35 +77,42 @@ class CardsFeed extends React.Component { } render() { - return this.props.feed.loaded && ( - - - { - (this.props.feed.loaded && !this.props.feed.allLoaded) - ?
this.props.loadMore(this.props.feed)} />
- : null - } - { this.props.items.length === 0 && ( -
{intl.get("article.empty")}
- )} -
+ return ( + this.props.feed.loaded && ( + + + {this.props.feed.loaded && !this.props.feed.allLoaded ? ( +
+ + this.props.loadMore(this.props.feed) + } + /> +
+ ) : null} + {this.props.items.length === 0 && ( +
{intl.get("article.empty")}
+ )} +
+ ) ) } } -export default CardsFeed \ No newline at end of file +export default CardsFeed diff --git a/src/components/feeds/feed.tsx b/src/components/feeds/feed.tsx index b189bdd..5fd8fa0 100644 --- a/src/components/feeds/feed.tsx +++ b/src/components/feeds/feed.tsx @@ -21,17 +21,15 @@ export type FeedProps = FeedReduxProps & { showItem: (fid: string, item: RSSItem) => void } -export class Feed extends React.Component { +export class Feed extends React.Component { render() { switch (this.props.viewType) { - case (ViewType.Cards): return ( - - ) - case (ViewType.Magazine): - case (ViewType.Compact): - case (ViewType.List): return ( - - ) + case ViewType.Cards: + return + case ViewType.Magazine: + case ViewType.Compact: + case ViewType.List: + return } } -} \ No newline at end of file +} diff --git a/src/components/feeds/list-feed.tsx b/src/components/feeds/list-feed.tsx index a30ab28..45e89bc 100644 --- a/src/components/feeds/list-feed.tsx +++ b/src/components/feeds/list-feed.tsx @@ -1,22 +1,27 @@ import * as React from "react" import intl from "react-intl-universal" import { FeedProps } from "./feed" -import { PrimaryButton, FocusZone, FocusZoneDirection, List } from 'office-ui-fabric-react'; -import { RSSItem } from "../../scripts/models/item"; -import { AnimationClassNames } from "@fluentui/react"; -import { ViewType } from "../../schema-types"; -import ListCard from "../cards/list-card"; -import MagazineCard from "../cards/magazine-card"; -import CompactCard from "../cards/compact-card"; -import { Card } from "../cards/card"; +import { + PrimaryButton, + FocusZone, + FocusZoneDirection, + List, +} from "office-ui-fabric-react" +import { RSSItem } from "../../scripts/models/item" +import { AnimationClassNames } from "@fluentui/react" +import { ViewType } from "../../schema-types" +import ListCard from "../cards/list-card" +import MagazineCard from "../cards/magazine-card" +import CompactCard from "../cards/compact-card" +import { Card } from "../cards/card" class ListFeed extends React.Component { onRenderItem = (item: RSSItem) => { const props = { feedId: this.props.feed._id, key: item._id, - item: item, - source: this.props.sourceMap[item.source], + item: item, + source: this.props.sourceMap[item.source], filter: this.props.filter, viewConfigs: this.props.viewConfigs, shortcuts: this.props.shortcuts, @@ -24,29 +29,40 @@ class ListFeed extends React.Component { contextMenu: this.props.contextMenu, showItem: this.props.showItem, } as Card.Props - if (this.props.viewType === ViewType.List && this.props.currentItem === item._id) { + if ( + this.props.viewType === ViewType.List && + this.props.currentItem === item._id + ) { props.selected = true } switch (this.props.viewType) { - case (ViewType.Magazine): return - case (ViewType.Compact): return - default: return + case ViewType.Magazine: + return + case ViewType.Compact: + return + default: + return } } getClassName = () => { switch (this.props.viewType) { - case (ViewType.Magazine): return "magazine-feed" - case (ViewType.Compact): return "compact-feed" - default: return "list-feed" + case ViewType.Magazine: + return "magazine-feed" + case ViewType.Compact: + return "compact-feed" + default: + return "list-feed" } } canFocusChild = (el: HTMLElement) => { if (el.id === "load-more") { const container = document.getElementById("refocus") - const result = container.scrollTop > container.scrollHeight - 2 * container.offsetHeight + const result = + container.scrollTop > + container.scrollHeight - 2 * container.offsetHeight if (!result) container.scrollTop += 100 return result } else { @@ -55,34 +71,41 @@ class ListFeed extends React.Component { } render() { - return this.props.feed.loaded && ( - - - { - (this.props.feed.loaded && !this.props.feed.allLoaded) - ?
this.props.loadMore(this.props.feed)} />
- : null - } - { this.props.items.length === 0 && ( -
{intl.get("article.empty")}
- )} -
+ return ( + this.props.feed.loaded && ( + + + {this.props.feed.loaded && !this.props.feed.allLoaded ? ( +
+ + this.props.loadMore(this.props.feed) + } + /> +
+ ) : null} + {this.props.items.length === 0 && ( +
{intl.get("article.empty")}
+ )} +
+ ) ) } } -export default ListFeed \ No newline at end of file +export default ListFeed diff --git a/src/components/log-menu.tsx b/src/components/log-menu.tsx index 7e7a80e..8f943cb 100644 --- a/src/components/log-menu.tsx +++ b/src/components/log-menu.tsx @@ -1,6 +1,12 @@ import * as React from "react" import intl from "react-intl-universal" -import { Callout, ActivityItem, Icon, DirectionalHint, Link } from "@fluentui/react" +import { + Callout, + ActivityItem, + Icon, + DirectionalHint, + Link, +} from "@fluentui/react" import { AppLog, AppLogType } from "../scripts/models/app" import Time from "./utils/time" @@ -13,46 +19,67 @@ type LogMenuProps = { function getLogIcon(log: AppLog) { switch (log.type) { - case AppLogType.Info: return "Info" - case AppLogType.Article: return "KnowledgeArticle" - default: return "Warning" + case AppLogType.Info: + return "Info" + case AppLogType.Article: + return "KnowledgeArticle" + default: + return "Warning" } } class LogMenu extends React.Component { - activityItems = () => this.props.logs.map((l, i) => ({ - key: i, - activityDescription: l.iid - ? this.handleArticleClick(l)}>{l.title} - : {l.title}, - comments: l.details, - activityIcon: , - timeStamp: