├── .assets ├── icons │ ├── Awesome Blazor Browser Icons Set.json │ ├── checkbox-blank.svg │ ├── checkbox-checked.svg │ ├── checkbox-indeterminate.svg │ ├── dark_mode_black_24dp.svg │ ├── expand-less.svg │ ├── expand-more.svg │ ├── light_mode_black_24dp.svg │ ├── link.svg │ ├── list_black_24dp.svg │ ├── logo-blazor-large.svg │ ├── mark-github.svg │ ├── menu_black_24dp.svg │ └── settings_black_24dp.svg └── movie-001.gif ├── .editorconfig ├── .github └── workflows │ └── gh-pages.yml ├── .gitignore ├── AwesomeBlazor.Models.Test ├── AwesomeBlazor.Models.Test.csproj ├── AwesomeBlazorParserTest.cs ├── AwesomeResourceFilterTest.cs ├── AwesomeResourceGroupTest.cs ├── AwesomeResourceGroupsExtensionsTest.cs ├── Sample.md └── TestFixture.cs ├── AwesomeBlazor.Models ├── AwesomeBlazor.Models.csproj ├── AwesomeBlazorParser.cs ├── AwesomeBlazorParserOptions.cs ├── AwesomeResource.cs ├── AwesomeResourceFilter.cs ├── AwesomeResourceGroup.cs ├── AwesomeResourceGroupsExtensions.cs ├── Properties │ └── AssemblyInfo.cs └── SelectionState.cs ├── AwesomeBlazorBrowser.slnx ├── AwesomeBlazorBrowser ├── .vscode │ ├── launch.json │ └── tasks.json ├── App.razor ├── App.razor.cs ├── App.razor.scss ├── AwesomeBlazorBrowser.csproj ├── Components │ ├── AppBar.razor │ ├── AppBar.razor.cs │ ├── AppBar.razor.scss │ ├── Contents.razor │ ├── Contents.razor.cs │ ├── Contents.razor.scss │ ├── Footer.razor │ ├── Footer.razor.scss │ ├── GroupSelector.razor │ ├── GroupSelector.razor.cs │ ├── GroupSelector.razor.scss │ ├── GroupsPanel.razor │ ├── GroupsPanel.razor.cs │ ├── GroupsPanel.razor.scss │ ├── Settings.razor │ ├── Settings.razor.cs │ └── Settings.razor.scss ├── HelperScriptService.cs ├── Program.cs ├── Properties │ ├── PublishProfiles │ │ └── for GitHub Pages.pubxml │ └── launchSettings.json ├── Theme.cs ├── ThemeExtension.cs ├── _Imports.razor ├── compilerconfig.json ├── compilerconfig.json.defaults ├── helper.ts ├── icons.scss ├── icons.variables.scss ├── site.mixin.scss ├── site.scss ├── site.theme.scss ├── site.variables.scss ├── theme-initializer.ts ├── toggle-box.scss ├── tsconfig.json └── wwwroot │ ├── css │ ├── fonts │ │ ├── Awesome-Blazor-Browser-Icons.svg │ │ ├── Awesome-Blazor-Browser-Icons.ttf │ │ └── Awesome-Blazor-Browser-Icons.woff │ ├── images │ │ └── ogp-image.png │ ├── site.css │ └── site.min.css │ ├── favicon.ico │ ├── index.html │ └── scripts │ ├── helper.js │ └── theme-initializer.js ├── LICENSE ├── README.md ├── THIRD-PARTY-NOTICES.txt └── global.json /.assets/icons/Awesome Blazor Browser Icons Set.json: -------------------------------------------------------------------------------- 1 | { 2 | "selection": [ 3 | { 4 | "order": 51, 5 | "name": "checkbox-blank", 6 | "prevSize": 32 7 | }, 8 | { 9 | "order": 52, 10 | "name": "checkbox-checked", 11 | "prevSize": 32 12 | }, 13 | { 14 | "order": 53, 15 | "name": "checkbox-indeterminate", 16 | "prevSize": 32 17 | }, 18 | { 19 | "order": 54, 20 | "name": "expand-less", 21 | "prevSize": 32 22 | }, 23 | { 24 | "order": 55, 25 | "name": "expand-more", 26 | "prevSize": 32 27 | }, 28 | { 29 | "order": 56, 30 | "name": "link", 31 | "prevSize": 32 32 | }, 33 | { 34 | "order": 57, 35 | "name": "logo-blazor-large", 36 | "prevSize": 32 37 | }, 38 | { 39 | "order": 58, 40 | "name": "mark-github", 41 | "prevSize": 32 42 | }, 43 | { 44 | "order": 59, 45 | "name": "list_black_24dp", 46 | "prevSize": 32 47 | }, 48 | { 49 | "order": 60, 50 | "name": "settings_black_24dp", 51 | "prevSize": 32 52 | }, 53 | { 54 | "order": 61, 55 | "name": "light_mode_black_24dp", 56 | "prevSize": 32 57 | }, 58 | { 59 | "order": 62, 60 | "name": "dark_mode_black_24dp", 61 | "prevSize": 32 62 | } 63 | ], 64 | "metadata": { 65 | "name": "Awesome Blazor Browser Icons Set", 66 | "importSize": { 67 | "width": 24, 68 | "height": 24 69 | }, 70 | "iconsHash": 1312725456 71 | }, 72 | "height": 1024, 73 | "prevSize": 32, 74 | "icons": [ 75 | { 76 | "paths": [ 77 | "M768 810.667h-512c-23.467 0-42.667-19.2-42.667-42.667v-512c0-23.467 19.2-42.667 42.667-42.667h512c23.467 0 42.667 19.2 42.667 42.667v512c0 23.467-19.2 42.667-42.667 42.667zM810.667 128h-597.333c-46.933 0-85.333 38.4-85.333 85.333v597.333c0 46.933 38.4 85.333 85.333 85.333h597.333c46.933 0 85.333-38.4 85.333-85.333v-597.333c0-46.933-38.4-85.333-85.333-85.333z" 78 | ], 79 | "grid": 0, 80 | "tags": [ 81 | "check_box_outline_blank-24px" 82 | ], 83 | "defaultCode": 59649 84 | }, 85 | { 86 | "paths": [ 87 | "M810.667 128h-597.333c-46.933 0-85.333 38.4-85.333 85.333v597.333c0 46.933 38.4 85.333 85.333 85.333h597.333c46.933 0 85.333-38.4 85.333-85.333v-597.333c0-46.933-38.4-85.333-85.333-85.333zM456.96 695.040c-16.64 16.64-43.52 16.64-60.16 0l-153.173-153.173c-16.64-16.64-16.64-43.52 0-60.16s43.52-16.64 60.16 0l122.88 122.88 293.547-293.547c16.64-16.64 43.52-16.64 60.16 0s16.64 43.52 0 60.16l-323.413 323.84z" 88 | ], 89 | "grid": 0, 90 | "tags": [ 91 | "check_box-24px" 92 | ], 93 | "defaultCode": 59650 94 | }, 95 | { 96 | "paths": [ 97 | "M810.667 128h-597.333c-46.933 0-85.333 38.4-85.333 85.333v597.333c0 46.933 38.4 85.333 85.333 85.333h597.333c46.933 0 85.333-38.4 85.333-85.333v-597.333c0-46.933-38.4-85.333-85.333-85.333zM725.333 554.667h-426.667v-85.333h426.667v85.333z" 98 | ], 99 | "grid": 0, 100 | "tags": [ 101 | "checkbox-indeterminate" 102 | ], 103 | "defaultCode": 59652 104 | }, 105 | { 106 | "paths": [ 107 | "M481.707 371.627l-195.84 195.84c-16.64 16.64-16.64 43.52 0 60.16s43.52 16.64 60.16 0l165.973-165.547 165.547 165.547c16.64 16.64 43.52 16.64 60.16 0s16.64-43.52 0-60.16l-195.84-195.84c-16.213-16.64-43.52-16.64-60.16 0z" 108 | ], 109 | "grid": 0, 110 | "tags": [ 111 | "expand_less-24px" 112 | ], 113 | "defaultCode": 59648 114 | }, 115 | { 116 | "paths": [ 117 | "M677.547 396.373l-165.547 165.547-165.547-165.547c-16.64-16.64-43.52-16.64-60.16 0s-16.64 43.52 0 60.16l195.84 195.84c16.64 16.64 43.52 16.64 60.16 0l195.84-195.84c16.64-16.64 16.64-43.52 0-60.16-16.64-16.213-43.947-16.64-60.587 0z" 118 | ], 119 | "grid": 0, 120 | "tags": [ 121 | "expand_more-24px" 122 | ], 123 | "defaultCode": 59651 124 | }, 125 | { 126 | "paths": [ 127 | "M256 576h64v64h-64c-96 0-192-108.16-192-224s99.2-224 192-224h256c92.8 0 192 108.16 192 224 0 90.24-58.24 174.080-128 208v-74.24c37.12-28.8 64-81.28 64-133.76 0-81.92-65.28-160-128-160h-256c-62.72 0-128 78.080-128 160s64 160 128 160zM832 384h-64v64h64c64 0 128 78.080 128 160s-65.28 160-128 160h-256c-62.72 0-128-78.080-128-160 0-53.12 26.88-104.96 64-133.76v-74.24c-69.76 33.92-128 117.76-128 208 0 115.84 99.2 224 192 224h256c92.8 0 192-108.16 192-224s-96-224-192-224z" 128 | ], 129 | "grid": 0, 130 | "tags": [ 131 | "link" 132 | ], 133 | "defaultCode": 59653 134 | }, 135 | { 136 | "paths": [ 137 | "M965.632 49.459c-1.331 0.717-5.222 6.451-9.421 13.824-33.178 59.392-65.638 99.84-103.731 129.536-35.021 27.238-79.155 48.947-129.843 63.693-20.48 5.939-22.63 4.096-13.21-11.469 22.938-37.99 38.81-82.227 45.363-126.771 2.56-17.92 2.56-19.763-0.614-21.197-3.072-1.331-6.042 0.307-10.752 6.246-4.096 5.018-24.166 23.245-35.84 32.461-38.502 30.413-87.245 53.658-135.168 64.307-31.744 6.963-31.744 6.963-130.048 7.782-56.627 0.512-93.389 1.229-99.84 1.946-50.381 5.837-92.467 18.534-136.192 40.96-35.738 18.33-62.157 37.478-91.238 66.15-85.094 84.173-125.952 200.704-112.538 321.024 8.294 74.445 36.352 143.258 81.101 199.168 11.469 14.438 34.509 37.99 48.947 50.176 54.989 46.49 124.109 75.878 199.066 84.992 40.755 4.915 99.533 3.482 149.606-3.686 102.4-14.541 193.126-54.886 268.39-119.398 16.998-14.643 44.954-42.189 44.954-44.442 0-1.126-0.307-1.946-0.614-1.946-0.41 0-6.042 3.379-12.595 7.475-103.629 65.331-230.298 101.069-358.195 101.069-23.347 0-54.784-1.946-73.421-4.608-149.606-20.992-262.451-133.427-279.654-278.528-3.072-26.214-1.741-65.946 3.174-92.672 10.65-58.163 38.4-113.664 78.848-157.901 42.598-46.49 101.683-80.794 162.714-94.515 26.829-6.042 37.376-7.066 70.144-7.066s43.315 1.024 70.144 7.066c72.090 16.179 138.342 59.494 183.603 119.91 35.328 47.206 56.934 105.472 62.771 169.677 1.638 18.227 0.717 48.538-1.946 60.928-12.288 56.422-49.766 95.539-98.509 102.707-10.342 1.434-29.901 0.717-40.96-1.638-27.238-5.632-49.766-19.456-64.614-39.424l-5.018-6.861-11.059 10.854c-11.981 11.981-24.678 20.992-40.141 28.774-43.315 21.709-94.618 21.197-138.035-1.536-14.95-7.782-25.6-15.77-38.605-28.672-21.914-21.709-36.147-48.026-43.008-79.36-2.253-10.342-3.174-37.888-1.638-49.664 4.608-34.816 19.763-65.331 45.158-90.624 22.426-22.528 48.128-36.454 79.77-43.213 9.114-2.048 14.029-2.15 66.56-2.56 49.664-0.41 57.651-0.205 65.024 1.229 24.371 4.915 43.315 22.63 50.483 47.104 1.536 5.427 1.843 13.824 2.355 74.24 0.717 75.571 0.512 72.704 7.885 87.859 6.963 14.234 19.763 23.962 35.942 27.341 26.112 5.632 47.411-4.71 59.187-28.672 7.066-14.438 8.806-22.323 9.318-44.544 1.024-39.834-7.168-76.083-25.805-114.278-13.21-26.829-28.672-48.026-51.405-70.042-32.358-31.539-70.246-52.941-113.357-64-19.866-5.12-32.563-6.758-55.91-7.373-32.563-0.819-56.934 2.662-87.040 12.595-16.691 5.53-44.749 19.149-58.88 28.57-49.869 33.28-86.118 82.022-103.219 138.752-9.626 31.949-13.107 68.198-9.523 99.328 6.451 55.501 33.382 107.827 76.595 148.992 21.299 20.275 42.906 35.123 70.963 48.742 45.568 22.221 87.040 29.696 156.16 28.16 61.542-1.331 107.213-8.090 160.256-23.654 166.912-49.254 308.326-172.544 377.754-329.421 30.925-69.939 45.466-135.987 47.411-215.347 1.946-82.842-13.107-154.931-45.568-216.986-6.144-11.776-8.192-13.722-12.493-11.571z", 138 | "M355.123 496.23c-34.304 6.144-62.771 32.256-72.704 66.458-2.048 7.168-2.355 10.342-2.355 25.6 0.102 16.282 0.307 17.92 2.97 26.112 5.734 17.306 12.902 28.672 25.907 41.062 31.949 30.515 80.896 33.587 117.658 7.578 8.192-5.837 20.48-19.046 25.293-27.238 5.018-8.499 9.318-19.866 11.366-29.798 1.331-6.554 1.638-16.282 1.638-58.061v-50.176l-2.253-1.536c-2.048-1.434-8.499-1.638-50.995-1.536-36.659 0.102-50.586 0.41-56.525 1.536z" 139 | ], 140 | "grid": 0, 141 | "tags": [ 142 | "logo-blazor-large" 143 | ], 144 | "defaultCode": 59654 145 | }, 146 | { 147 | "paths": [ 148 | "M512 0c-282.88 0-512 229.12-512 512 0 226.56 146.56 417.92 350.080 485.76 25.6 4.48 35.2-10.88 35.2-24.32 0-12.16-0.64-52.48-0.64-95.36-128.64 23.68-161.92-31.36-172.16-60.16-5.76-14.72-30.72-60.16-52.48-72.32-17.92-9.6-43.52-33.28-0.64-33.92 40.32-0.64 69.12 37.12 78.72 52.48 46.080 77.44 119.68 55.68 149.12 42.24 4.48-33.28 17.92-55.68 32.64-68.48-113.92-12.8-232.96-56.96-232.96-252.8 0-55.68 19.84-101.76 52.48-137.6-5.12-12.8-23.040-65.28 5.12-135.68 0 0 42.88-13.44 140.8 52.48 40.96-11.52 84.48-17.28 128-17.28s87.040 5.76 128 17.28c97.92-66.56 140.8-52.48 140.8-52.48 28.16 70.4 10.24 122.88 5.12 135.68 32.64 35.84 52.48 81.28 52.48 137.6 0 196.48-119.68 240-233.6 252.8 18.56 16 34.56 46.72 34.56 94.72 0 68.48-0.64 123.52-0.64 140.8 0 13.44 9.6 29.44 35.2 24.32 204.471-70.528 348.741-261.288 348.8-485.753l0-0.007c0-282.88-229.12-512-512-512z" 149 | ], 150 | "grid": 0, 151 | "tags": [ 152 | "mark-github" 153 | ], 154 | "defaultCode": 59655 155 | }, 156 | { 157 | "paths": [ 158 | "M128 554.667h85.333v-85.333h-85.333v85.333zM128 725.333h85.333v-85.333h-85.333v85.333zM128 384h85.333v-85.333h-85.333v85.333zM298.667 554.667h597.333v-85.333h-597.333v85.333zM298.667 725.333h597.333v-85.333h-597.333v85.333zM298.667 298.667v85.333h597.333v-85.333h-597.333z" 159 | ], 160 | "grid": 0, 161 | "tags": [ 162 | "list_black_24dp" 163 | ], 164 | "defaultCode": 59656 165 | }, 166 | { 167 | "paths": [ 168 | "M829.013 553.813c1.707-13.653 2.987-27.307 2.987-41.813s-1.28-28.16-2.987-41.813l90.027-70.4c8.107-6.4 10.24-17.92 5.12-27.307l-85.333-147.627c-3.84-6.827-11.093-10.667-18.773-10.667-2.56 0-5.12 0.427-7.253 1.28l-106.24 42.667c-22.187-17.067-46.080-31.147-72.107-41.813l-16.213-113.067c-1.28-10.24-10.24-17.92-20.907-17.92h-170.667c-10.667 0-19.627 7.68-20.907 17.92l-16.213 113.067c-26.027 10.667-49.92 25.173-72.107 41.813l-106.24-42.667c-2.56-0.853-5.12-1.28-7.68-1.28-7.253 0-14.507 3.84-18.347 10.667l-85.333 147.627c-5.547 9.387-2.987 20.907 5.12 27.307l90.027 70.4c-1.707 13.653-2.987 27.733-2.987 41.813s1.28 28.16 2.987 41.813l-90.027 70.4c-8.107 6.4-10.24 17.92-5.12 27.307l85.333 147.627c3.84 6.827 11.093 10.667 18.773 10.667 2.56 0 5.12-0.427 7.253-1.28l106.24-42.667c22.187 17.067 46.080 31.147 72.107 41.813l16.213 113.067c1.28 10.24 10.24 17.92 20.907 17.92h170.667c10.667 0 19.627-7.68 20.907-17.92l16.213-113.067c26.027-10.667 49.92-25.173 72.107-41.813l106.24 42.667c2.56 0.853 5.12 1.28 7.68 1.28 7.253 0 14.507-3.84 18.347-10.667l85.333-147.627c5.12-9.387 2.987-20.907-5.12-27.307l-90.027-70.4zM744.533 480.853c1.707 13.227 2.133 22.187 2.133 31.147s-0.853 18.347-2.133 31.147l-5.973 48.213 37.973 29.867 46.080 35.84-29.867 51.627-54.187-21.76-44.373-17.92-38.4 29.013c-18.347 13.653-35.84 23.893-53.333 31.147l-45.227 18.347-6.827 48.213-8.533 57.6h-59.733l-8.107-57.6-6.827-48.213-45.227-18.347c-18.347-7.68-35.413-17.493-52.48-30.293l-38.827-29.867-45.227 18.347-54.187 21.76-29.867-51.627 46.080-35.84 37.973-29.867-5.973-48.213c-1.28-13.227-2.133-23.040-2.133-31.573s0.853-18.347 2.133-31.147l5.973-48.213-37.973-29.867-46.080-35.84 29.867-51.627 54.187 21.76 44.373 17.92 38.4-29.013c18.347-13.653 35.84-23.893 53.333-31.147l45.227-18.347 6.827-48.213 8.533-57.6h59.307l8.107 57.6 6.827 48.213 45.227 18.347c18.347 7.68 35.413 17.493 52.48 30.293l38.827 29.867 45.227-18.347 54.187-21.76 29.867 51.627-45.653 36.267-37.973 29.867 5.973 48.213zM512 341.333c-94.293 0-170.667 76.373-170.667 170.667s76.373 170.667 170.667 170.667 170.667-76.373 170.667-170.667-76.373-170.667-170.667-170.667zM512 597.333c-46.933 0-85.333-38.4-85.333-85.333s38.4-85.333 85.333-85.333 85.333 38.4 85.333 85.333-38.4 85.333-85.333 85.333z" 169 | ], 170 | "grid": 0, 171 | "tags": [ 172 | "settings_black_24dp" 173 | ], 174 | "defaultCode": 59657 175 | }, 176 | { 177 | "paths": [ 178 | "M512 298.667c-117.76 0-213.333 95.573-213.333 213.333s95.573 213.333 213.333 213.333 213.333-95.573 213.333-213.333-95.573-213.333-213.333-213.333v0zM85.333 554.667h85.333c23.467 0 42.667-19.2 42.667-42.667s-19.2-42.667-42.667-42.667h-85.333c-23.467 0-42.667 19.2-42.667 42.667s19.2 42.667 42.667 42.667zM853.333 554.667h85.333c23.467 0 42.667-19.2 42.667-42.667s-19.2-42.667-42.667-42.667h-85.333c-23.467 0-42.667 19.2-42.667 42.667s19.2 42.667 42.667 42.667zM469.333 85.333v85.333c0 23.467 19.2 42.667 42.667 42.667s42.667-19.2 42.667-42.667v-85.333c0-23.467-19.2-42.667-42.667-42.667s-42.667 19.2-42.667 42.667zM469.333 853.333v85.333c0 23.467 19.2 42.667 42.667 42.667s42.667-19.2 42.667-42.667v-85.333c0-23.467-19.2-42.667-42.667-42.667s-42.667 19.2-42.667 42.667zM255.573 195.413c-16.64-16.64-43.947-16.64-60.16 0-16.64 16.64-16.64 43.947 0 60.16l45.227 45.227c16.64 16.64 43.947 16.64 60.16 0s16.64-43.947 0-60.16l-45.227-45.227zM783.36 723.2c-16.64-16.64-43.947-16.64-60.16 0-16.64 16.64-16.64 43.947 0 60.16l45.227 45.227c16.64 16.64 43.947 16.64 60.16 0 16.64-16.64 16.64-43.947 0-60.16l-45.227-45.227zM828.587 255.573c16.64-16.64 16.64-43.947 0-60.16-16.64-16.64-43.947-16.64-60.16 0l-45.227 45.227c-16.64 16.64-16.64 43.947 0 60.16s43.947 16.64 60.16 0l45.227-45.227zM300.8 783.36c16.64-16.64 16.64-43.947 0-60.16-16.64-16.64-43.947-16.64-60.16 0l-45.227 45.227c-16.64 16.64-16.64 43.947 0 60.16s43.947 16.64 60.16 0l45.227-45.227z" 179 | ], 180 | "grid": 0, 181 | "tags": [ 182 | "light_mode_black_24dp" 183 | ], 184 | "defaultCode": 59658 185 | }, 186 | { 187 | "paths": [ 188 | "M512 128c-212.053 0-384 171.947-384 384s171.947 384 384 384 384-171.947 384-384c0-19.627-1.707-39.253-4.267-58.027-41.813 58.453-110.080 96.427-187.733 96.427-127.147 0-230.4-103.253-230.4-230.4 0-77.227 37.973-145.92 96.427-187.733-18.773-2.56-38.4-4.267-58.027-4.267v0z" 189 | ], 190 | "grid": 0, 191 | "tags": [ 192 | "dark_mode_black_24dp" 193 | ], 194 | "defaultCode": 59659 195 | } 196 | ], 197 | "colorThemes": [], 198 | "preferences": { 199 | "showGlyphs": true, 200 | "showQuickUse": true, 201 | "showQuickUse2": true, 202 | "showSVGs": true, 203 | "fontPref": { 204 | "prefix": "icon-", 205 | "metadata": { 206 | "fontFamily": "Awesome-Blazor-Browser-Icons", 207 | "majorVersion": 1, 208 | "minorVersion": 0 209 | }, 210 | "metrics": { 211 | "emSize": 1024, 212 | "baseline": 6.25, 213 | "whitespace": 50 214 | }, 215 | "embed": false, 216 | "autoHost": false, 217 | "noie8": true, 218 | "ie7": false, 219 | "showSelector": true, 220 | "selector": "class", 221 | "classSelector": ".icon", 222 | "showMetrics": true, 223 | "showMetadata": true, 224 | "showVersion": true, 225 | "cssVars": true, 226 | "cssVarsFormat": "scss" 227 | }, 228 | "imagePref": { 229 | "prefix": "icon-", 230 | "png": true, 231 | "useClassSelector": true, 232 | "color": 0, 233 | "bgColor": 16777215, 234 | "classSelector": ".icon" 235 | }, 236 | "historySize": 50, 237 | "showCodes": true, 238 | "gridSize": 16, 239 | "quickUsageToken": { 240 | "UntitledProject": "YWM4YTA1YWFlM2ViMWI3M2ZkNTliNDAwYmZhMmRmOTUjMSMxNTg4NDcwMTgzIyMj" 241 | } 242 | }, 243 | "IcoMoonType": "icon-set" 244 | } -------------------------------------------------------------------------------- /.assets/icons/checkbox-blank.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.assets/icons/checkbox-checked.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.assets/icons/checkbox-indeterminate.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.assets/icons/dark_mode_black_24dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.assets/icons/expand-less.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.assets/icons/expand-more.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.assets/icons/light_mode_black_24dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.assets/icons/link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.assets/icons/list_black_24dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.assets/icons/logo-blazor-large.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 10 | 35 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /.assets/icons/mark-github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.assets/icons/menu_black_24dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.assets/icons/settings_black_24dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.assets/movie-001.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/awesome-blazor-browser/889c29665008edc994b9b551d46d21a6fe848eeb/.assets/movie-001.gif -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.csproj] 2 | indent_style = space 3 | indent_size = 2 4 | [*.{cs,vb}] 5 | #### Naming styles #### 6 | 7 | # Naming rules 8 | 9 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 10 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 11 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 12 | 13 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 14 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 15 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 16 | 17 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 18 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 19 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 20 | 21 | # Symbol specifications 22 | 23 | dotnet_naming_symbols.interface.applicable_kinds = interface 24 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 25 | dotnet_naming_symbols.interface.required_modifiers = 26 | 27 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 28 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 29 | dotnet_naming_symbols.types.required_modifiers = 30 | 31 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 32 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 33 | dotnet_naming_symbols.non_field_members.required_modifiers = 34 | 35 | # Naming styles 36 | 37 | dotnet_naming_style.begins_with_i.required_prefix = I 38 | dotnet_naming_style.begins_with_i.required_suffix = 39 | dotnet_naming_style.begins_with_i.word_separator = 40 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 41 | 42 | dotnet_naming_style.pascal_case.required_prefix = 43 | dotnet_naming_style.pascal_case.required_suffix = 44 | dotnet_naming_style.pascal_case.word_separator = 45 | dotnet_naming_style.pascal_case.capitalization = pascal_case 46 | 47 | dotnet_naming_style.pascal_case.required_prefix = 48 | dotnet_naming_style.pascal_case.required_suffix = 49 | dotnet_naming_style.pascal_case.word_separator = 50 | dotnet_naming_style.pascal_case.capitalization = pascal_case 51 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 52 | tab_width = 4 53 | indent_size = 4 54 | end_of_line = crlf 55 | dotnet_style_coalesce_expression = true:suggestion 56 | dotnet_style_null_propagation = true:suggestion 57 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 58 | dotnet_style_prefer_auto_properties = true:silent 59 | dotnet_style_object_initializer = true:suggestion 60 | dotnet_style_collection_initializer = true:suggestion 61 | dotnet_style_prefer_simplified_boolean_expressions = true:suggestion 62 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 63 | dotnet_style_prefer_conditional_expression_over_return = true:silent 64 | dotnet_style_explicit_tuple_names = true:suggestion 65 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 66 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 67 | dotnet_style_prefer_compound_assignment = true:suggestion 68 | dotnet_style_prefer_simplified_interpolation = true:suggestion 69 | dotnet_style_namespace_match_folder = true:suggestion 70 | dotnet_style_readonly_field = true:suggestion 71 | dotnet_style_qualification_for_field = true:warning 72 | dotnet_style_qualification_for_property = true:warning 73 | dotnet_style_qualification_for_method = true:warning 74 | dotnet_style_qualification_for_event = true:warning 75 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent 76 | dotnet_style_predefined_type_for_member_access = true:silent 77 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent 78 | dotnet_style_allow_multiple_blank_lines_experimental = true:silent 79 | dotnet_style_allow_statement_immediately_after_block_experimental = true:silent 80 | dotnet_code_quality_unused_parameters = all:suggestion 81 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent 82 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent 83 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent 84 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent 85 | dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion 86 | 87 | [*.cs] 88 | csharp_indent_labels = one_less_than_current 89 | csharp_space_around_binary_operators = before_and_after 90 | csharp_using_directive_placement = outside_namespace:silent 91 | csharp_prefer_simple_using_statement = true:suggestion 92 | csharp_prefer_braces = true:silent 93 | csharp_style_namespace_declarations = file_scoped:suggestion 94 | csharp_style_prefer_method_group_conversion = true:silent 95 | csharp_style_expression_bodied_methods = false:silent 96 | csharp_style_expression_bodied_constructors = false:silent 97 | csharp_style_expression_bodied_operators = false:silent 98 | csharp_style_expression_bodied_properties = true:silent 99 | csharp_style_expression_bodied_indexers = true:silent 100 | csharp_style_expression_bodied_accessors = true:silent 101 | csharp_style_expression_bodied_lambdas = true:silent 102 | csharp_style_expression_bodied_local_functions = false:silent 103 | csharp_style_throw_expression = true:suggestion 104 | csharp_style_prefer_null_check_over_type_check = true:suggestion 105 | csharp_prefer_simple_default_expression = true:suggestion 106 | csharp_style_prefer_local_over_anonymous_function = true:suggestion 107 | csharp_style_prefer_index_operator = true:suggestion 108 | csharp_style_prefer_range_operator = true:suggestion 109 | csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion 110 | csharp_style_prefer_tuple_swap = true:suggestion 111 | csharp_style_inlined_variable_declaration = true:suggestion 112 | csharp_style_deconstructed_variable_declaration = true:suggestion 113 | csharp_style_unused_value_assignment_preference = discard_variable:suggestion 114 | csharp_style_unused_value_expression_statement_preference = discard_variable:silent 115 | csharp_prefer_static_local_function = true:suggestion 116 | csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent 117 | csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent 118 | csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent 119 | csharp_style_conditional_delegate_call = true:suggestion 120 | csharp_style_prefer_parameter_null_checking = true:suggestion 121 | csharp_style_prefer_switch_expression = true:suggestion 122 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 123 | csharp_style_prefer_pattern_matching = true:silent 124 | csharp_style_prefer_not_pattern = true:suggestion 125 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 126 | csharp_style_prefer_extended_property_pattern = true:suggestion 127 | csharp_style_var_for_built_in_types = true:warning 128 | csharp_style_var_when_type_is_apparent = true:warning 129 | csharp_style_var_elsewhere = true:warning 130 | csharp_style_prefer_top_level_statements = true:silent 131 | csharp_style_prefer_primary_constructors = true:suggestion 132 | csharp_style_prefer_utf8_string_literals = true:suggestion 133 | csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent 134 | csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: github pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | schedule: 8 | - cron: "0 12 * * *" 9 | 10 | jobs: 11 | deploy: 12 | runs-on: ubuntu-latest 13 | steps: 14 | # Checkout the code 15 | - uses: actions/checkout@v4 16 | 17 | # Install .NET SDK 18 | - name: Setup .NET SDK 19 | uses: actions/setup-dotnet@v4 20 | with: 21 | dotnet-version: 10.0.x 22 | dotnet-quality: 'preview' 23 | - name: Install .NET WebAssembly Tools 24 | run: dotnet workload install wasm-tools 25 | 26 | # Publish the site 27 | - name: Publish 28 | run: dotnet publish AwesomeBlazorBrowser/AwesomeBlazorBrowser.csproj -c:Release -o:public -p:GHPages=true 29 | 30 | # Deploy the site 31 | - name: Deploy 32 | uses: peaceiris/actions-gh-pages@v4 33 | with: 34 | github_token: ${{ secrets.GITHUB_TOKEN }} 35 | publish_dir: public/wwwroot 36 | force_orphan: true 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | bin/ 3 | obj/ 4 | *.user 5 | *.suo 6 | /AwesomeBlazorBrowser.PreRenderer/Properties/launchSettings.json 7 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models.Test/AwesomeBlazor.Models.Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net10.0 5 | false 6 | enable 7 | enable 8 | $(WarningsAsErrors);nullable 9 | true 10 | Exe 11 | true 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | all 24 | runtime; build; native; contentfiles; analyzers; buildtransitive 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | PreserveNewest 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models.Test/AwesomeBlazorParserTest.cs: -------------------------------------------------------------------------------- 1 | namespace AwesomeBlazor.Models.Test; 2 | 3 | public class AwesomeBlazorParserTest 4 | { 5 | [Test] 6 | public void Parse_Test() 7 | { 8 | var contents = TestFixture.GetContentsForTest(); 9 | var root = AwesomeBlazorParser.ParseMarkdown(contents); 10 | 11 | root.Resources.Any().IsFalse(); 12 | root.SubGroups.Select(g => g.Title) 13 | .Is("Awesome Blazor", 14 | "Special event: \"Virtual Meetup\". [TODAY!]", 15 | "Introduction", "General", "Sample Projects", "Tutorials"); 16 | 17 | var topTitle = root.SubGroups[0]; 18 | topTitle.SelectionState.Is(SelectionState.Selected); 19 | topTitle.Resources.Any().IsFalse(); 20 | topTitle.SubGroups.Any().IsFalse(); 21 | topTitle.ParagraphsHtml.IsNot(""); 22 | 23 | var specialEvent = root.SubGroups[1]; 24 | specialEvent.SelectionState.Is(SelectionState.Selected); 25 | specialEvent.Resources.Any().IsFalse(); 26 | specialEvent.SubGroups.Any().IsFalse(); 27 | specialEvent.ParagraphsHtml.IsNot(""); 28 | 29 | var introduction = root.SubGroups[2]; 30 | introduction.SelectionState.Is(SelectionState.Selected); 31 | introduction.ParagraphsHtml.Is(""); 32 | introduction.Resources.Any().IsFalse(); 33 | introduction.SubGroups.Select(g => g.Title) 34 | .Is("What is Blazor", "Get started"); 35 | 36 | var whatsBlazor = introduction.SubGroups[0]; 37 | whatsBlazor.SelectionState.Is(SelectionState.Selected); 38 | whatsBlazor.Resources.Any().IsFalse(); 39 | whatsBlazor.SubGroups.Any().IsFalse(); 40 | whatsBlazor.ParagraphsHtml.IsNot(""); 41 | 42 | var getStarted = introduction.SubGroups[1]; 43 | getStarted.SelectionState.Is(SelectionState.Selected); 44 | getStarted.Resources.Any().IsFalse(); 45 | getStarted.SubGroups.Any().IsFalse(); 46 | getStarted.ParagraphsHtml.IsNot(""); 47 | 48 | var general = root.SubGroups[3]; 49 | general.SelectionState.Is(SelectionState.Selected); 50 | general.SubGroups.Any().IsFalse(); 51 | general.ParagraphsHtml.Is(""); 52 | general.Resources.Select(r => $"{r.Title} | {r.ResourceUrl}") 53 | .Is("ASP.NET Blog's archives | https://devblogs.microsoft.com/aspnet/category/blazor/", 54 | "eShopOnBlazor | https://github.com/dotnet-architecture/eShopOnBlazor"); 55 | 56 | var sampleProjects = root.SubGroups[4]; 57 | sampleProjects.SelectionState.Is(SelectionState.Selected); 58 | sampleProjects.ParagraphsHtml.Is(""); 59 | sampleProjects.Resources.Any().IsFalse(); 60 | sampleProjects.SubGroups.Select(g => g.Title) 61 | .Is("Authentication", "Cloud"); 62 | 63 | var authentication = sampleProjects.SubGroups[0]; 64 | authentication.SelectionState.Is(SelectionState.Selected); 65 | authentication.SubGroups.Any().IsFalse(); 66 | authentication.ParagraphsHtml.Is(""); 67 | authentication.Resources.Select(r => $"{r.Title} | {r.ResourceUrl}") 68 | .Is("BlazorBoilerplate | https://github.com/enkodellc/blazorboilerplate"); 69 | 70 | var cloud = sampleProjects.SubGroups[1]; 71 | cloud.SelectionState.Is(SelectionState.Selected); 72 | cloud.SubGroups.Any().IsFalse(); 73 | cloud.ParagraphsHtml.Is(""); 74 | cloud.Resources.Select(r => $"{r.Title} | {r.ResourceUrl}") 75 | .Is("BlazorAzure.WebApp | https://github.com/gpeipman/BlazorDemo/tree/master/BlazorAzure.WebApp", 76 | "BlazorFile2Azure | https://github.com/daltskin/BlazorFile2Azure"); 77 | 78 | var tutorials = root.SubGroups[5]; 79 | tutorials.SelectionState.Is(SelectionState.Selected); 80 | tutorials.SubGroups.Any().IsFalse(); 81 | tutorials.ParagraphsHtml.Is(""); 82 | tutorials.Resources.Select(r => $"{r.Title} | {r.ResourceUrl}") 83 | .Is("Blazor workshop | https://github.com/dotnet-presentations/blazor-workshop/"); 84 | } 85 | 86 | [Test] 87 | public void ParseAsResource_Simplest_Test() 88 | { 89 | AwesomeBlazorParser.TryParseAsResource( 90 | "* [Fizz Buzz](https://github.com/fizz/buzz) - " + 91 | "This is fizz buzz. ", 92 | out var resource 93 | ).IsTrue(); 94 | 95 | resource.IsNotNull(); 96 | resource.Title.Is("Fizz Buzz"); 97 | resource.ResourceUrl.Is("https://github.com/fizz/buzz"); 98 | resource.GitHubStarsUrl.Is(""); 99 | resource.LastCommitUrl.Is(""); 100 | resource.DescriptionText.Is("This is fizz buzz."); 101 | } 102 | 103 | [Test] 104 | public void ParseAsResource_FullSet_Test() 105 | { 106 | AwesomeBlazorParser.TryParseAsResource( 107 | "* [Foo Bar](https://github.com/foo/bar) - " + 108 | "![GitHub stars](https://img.shields.io/github/stars/foo/bar?style=flat-square&cacheSeconds=604800&logo=foo) " + 109 | "![last commit](https://img.shields.io/github/last-commit/foo/bar?style=flat-square&cacheSeconds=86400) " + 110 | "![custom badge](https://img.shields.io/foo) This is `foo` and . " + 111 | "[Demo](https://foo.bar.example.com) and [[Video]](https://youtube.com/).", 112 | out var resource 113 | ).IsTrue(); 114 | 115 | resource.IsNotNull(); 116 | resource.Title.Is("Foo Bar"); 117 | resource.ResourceUrl.Is("https://github.com/foo/bar"); 118 | resource.GitHubStarsUrl.Is("https://img.shields.io/github/stars/foo/bar?style=flat-square&cacheSeconds=604800&logo=foo"); 119 | resource.LastCommitUrl.Is("https://img.shields.io/github/last-commit/foo/bar?style=flat-square&cacheSeconds=86400"); 120 | resource.DescriptionText.Is("This is foo and . Demo and [Video]."); 121 | resource.DescriptionHtml.Is( 122 | "\"custom " + 123 | "This is foo and . " + 124 | "Demo and " + 125 | "[Video]."); 126 | } 127 | 128 | [Test] 129 | public void ParseAsResource_with_Missing_Hyphen_Test() 130 | { 131 | AwesomeBlazorParser.TryParseAsResource( 132 | "* [Fizz Buzz](https://github.com/fizz/buzz) " + 133 | "This is fizz buzz. ", 134 | out var resource 135 | ).IsTrue(); 136 | 137 | resource.IsNotNull(); 138 | resource.Title.Is("Fizz Buzz"); 139 | resource.ResourceUrl.Is("https://github.com/fizz/buzz"); 140 | resource.GitHubStarsUrl.Is(""); 141 | resource.LastCommitUrl.Is(""); 142 | resource.DescriptionText.Is("This is fizz buzz."); 143 | } 144 | 145 | [Test] 146 | public void ParseAsResource_with_Missing_Bullet_Test() 147 | { 148 | AwesomeBlazorParser.TryParseAsResource( 149 | "[Fizz Buzz](https://github.com/fizz/buzz) " + 150 | "This is fizz buzz. ", 151 | out var resource 152 | ).IsTrue(); 153 | 154 | resource.IsNotNull(); 155 | resource.Title.Is("Fizz Buzz"); 156 | resource.ResourceUrl.Is("https://github.com/fizz/buzz"); 157 | resource.GitHubStarsUrl.Is(""); 158 | resource.LastCommitUrl.Is(""); 159 | resource.DescriptionText.Is("This is fizz buzz."); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models.Test/AwesomeResourceFilterTest.cs: -------------------------------------------------------------------------------- 1 | namespace AwesomeBlazor.Models.Test; 2 | 3 | public class AwesomeResourceFilterTest 4 | { 5 | [Test] 6 | public void UpdateVisibiltyByKeywordFilter_Hit_in_Description_Test() 7 | { 8 | var contents = TestFixture.GetContentsForTest(); 9 | var root = AwesomeBlazorParser.ParseMarkdown(contents); 10 | 11 | root.SubGroups.UpdateVisibiltyByKeywordFilter(".net"); 12 | var visibleGroups = root.SubGroups.Where(g => g.Visible).ToArray(); 13 | visibleGroups.Select(g => g.Title) 14 | .Is("General", "Tutorials"); 15 | 16 | var general = visibleGroups[0]; 17 | general.Resources 18 | .Where(r => r.Visible) 19 | .Select(r => r.Title) 20 | .Is("ASP.NET Blog's archives", "eShopOnBlazor"); 21 | 22 | var tutorials = visibleGroups[1]; 23 | tutorials.Resources 24 | .Where(r => r.Visible) 25 | .Select(r => r.Title) 26 | .Is("Blazor workshop"); 27 | } 28 | 29 | [Test] 30 | public void UpdateVisibiltyByKeywordFilter_Hit_in_Level2_Title_Test() 31 | { 32 | var contents = TestFixture.GetContentsForTest(); 33 | var root = AwesomeBlazorParser.ParseMarkdown(contents); 34 | 35 | root.SubGroups.UpdateVisibiltyByKeywordFilter("file2"); 36 | var visibleGroups = root.SubGroups.Where(g => g.Visible).ToArray(); 37 | visibleGroups 38 | .Select(g => g.Title) 39 | .Is("Sample Projects"); 40 | 41 | var sampleProject = visibleGroups[0]; 42 | sampleProject.SubGroups 43 | .Where(g => g.Visible) 44 | .Select(g => g.Title) 45 | .Is("Cloud"); 46 | 47 | var cloud = sampleProject.SubGroups.First(g => g.Visible); 48 | cloud.Resources 49 | .Where(r => r.Visible) 50 | .Select(r => r.Title) 51 | .Is("BlazorFile2Azure"); 52 | } 53 | 54 | [Test] 55 | public void UpdateVisibiltyByKeywordFilter_Hit_MultiKeywords_Test() 56 | { 57 | var contents = TestFixture.GetContentsForTest(); 58 | var root = AwesomeBlazorParser.ParseMarkdown(contents); 59 | 60 | root.SubGroups.UpdateVisibiltyByKeywordFilter(".net shop microsoft"); 61 | var visibleGroups = root.SubGroups.Where(g => g.Visible).ToArray(); 62 | visibleGroups 63 | .Select(g => g.Title) 64 | .Is("General"); 65 | 66 | var general = visibleGroups[0]; 67 | general.Resources 68 | .Where(r => r.Visible) 69 | .Select(r => r.Title) 70 | .Is("eShopOnBlazor"); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models.Test/AwesomeResourceGroupTest.cs: -------------------------------------------------------------------------------- 1 | namespace AwesomeBlazor.Models.Test; 2 | 3 | public class AwesomeResourceGroupTest 4 | { 5 | [Test] 6 | public void SelectionState_Test() 7 | { 8 | var contents = TestFixture.GetContentsForTest(); 9 | var root = AwesomeBlazorParser.ParseMarkdown(contents); 10 | 11 | var parentGroup = root.SubGroups[4]; 12 | var childGroup1 = parentGroup.SubGroups[0]; 13 | var childGroup2 = parentGroup.SubGroups[1]; 14 | 15 | childGroup1.SelectionState = SelectionState.Unselected; 16 | parentGroup.SelectionState.Is(SelectionState.SelectedAny); 17 | 18 | parentGroup.SelectionState = SelectionState.Selected; 19 | childGroup1.SelectionState.Is(SelectionState.Selected); 20 | childGroup2.SelectionState.Is(SelectionState.Selected); 21 | 22 | childGroup1.SelectionState = SelectionState.Unselected; 23 | childGroup2.SelectionState = SelectionState.Unselected; 24 | parentGroup.SelectionState.Is(SelectionState.Unselected); 25 | 26 | childGroup1.SelectionState = SelectionState.Selected; 27 | childGroup2.SelectionState = SelectionState.Selected; 28 | parentGroup.SelectionState.Is(SelectionState.Selected); 29 | 30 | parentGroup.SelectionState = SelectionState.Unselected; 31 | childGroup1.SelectionState.Is(SelectionState.Unselected); 32 | childGroup2.SelectionState.Is(SelectionState.Unselected); 33 | } 34 | 35 | [Test] 36 | public void GetExpandedDescendantsCount_Test() 37 | { 38 | var root = new AwesomeResourceGroup 39 | { 40 | Expanded = true, 41 | SubGroups = { 42 | new AwesomeResourceGroup { }, // 1 43 | new AwesomeResourceGroup { // 2 44 | Expanded = true, 45 | SubGroups = { 46 | new AwesomeResourceGroup { }, // 3 47 | new AwesomeResourceGroup { } // 4 48 | } 49 | }, 50 | new AwesomeResourceGroup { }, // 5 51 | new AwesomeResourceGroup { // 6 52 | Expanded = false, 53 | SubGroups = { 54 | new AwesomeResourceGroup { }, // No Count due to collapsed 55 | new AwesomeResourceGroup { } 56 | } 57 | } 58 | } 59 | }; 60 | root.GetExpandedDescendantsCount().Is(6); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models.Test/AwesomeResourceGroupsExtensionsTest.cs: -------------------------------------------------------------------------------- 1 | namespace AwesomeBlazor.Models.Test; 2 | 3 | public class AwesomeResourceGroupsExtensionsTest 4 | { 5 | [Test] 6 | public void EnumGroupsDescendants_Test() 7 | { 8 | var contents = TestFixture.GetContentsForTest(); 9 | var root = AwesomeBlazorParser.ParseMarkdown(contents); 10 | 11 | root.SubGroups.EnumGroupsDescendants() 12 | .Select(g => g.Title) 13 | .Is( 14 | "Awesome Blazor", 15 | "Special event: \"Virtual Meetup\". [TODAY!]", 16 | "Introduction", 17 | "What is Blazor", 18 | "Get started", 19 | "General", 20 | "Sample Projects", 21 | "Authentication", 22 | "Cloud", 23 | "Tutorials"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models.Test/Sample.md: -------------------------------------------------------------------------------- 1 | # Awesome Blazor [![Awesome](https://awesome.re/badge-flat2.svg)](https://awesome.re) 2 | [](https://dotnet.microsoft.com/apps/aspnet/web-apps/client) 3 | 4 | > A collection of awesome Blazor resources. 5 | 6 | Blazor is a .NET web framework using C#/Razor and HTML that runs in the browser with WebAssembly. 7 | 8 | Contributions are always welcome! Please take a look at the [contribution guidelines](https://github.com/AdrienTorris/awesome-blazor/blob/master/CONTRIBUTING.md) pages first. Thanks to all [contributors](https://github.com/AdrienTorris/awesome-blazor/graphs/contributors), you're awesome and wouldn't be possible without you! 9 | 10 | ## Special event: "Virtual Meetup". [TODAY!] 11 | [](https://www.meetup.com/fr-FR/dotnetsouthwest/events/270194696/) 12 | - Virtual Meetup - What is Blazor? And why’s it so exciting? by Chris Sainty 13 | 14 | ## Contents 15 | * [General](#general) 16 | * [Sample Projects](#sample-projects) 17 | * [Tutorials](#tutorials) 18 | 19 | ## Introduction 20 | 21 | ### What is Blazor 22 | Blazor is a .NET web framework to build client web apps with C#. 23 | 24 | More information on the [official Blazor website](https://blazor.net). 25 | 26 | ### Get started 27 | 28 | To get started with Blazor, follow the instructions in the [Blazor Get Started](https://docs.microsoft.com/aspnet/core/blazor/get-started) documentation. 29 | 30 | To open Blazor projects in Visual Studio, you must have [Visual Studio 2019 16.3](https://www.visualstudio.com/vs/) or later and the [.NET Core 3.0 SDK](https://dot.net/get-core3). 31 | 32 | ## General 33 | * [ASP.NET Blog's archives](https://devblogs.microsoft.com/aspnet/category/blazor/) - Archives of the ASP.NET blog about Blazor. 34 | * [eShopOnBlazor](https://github.com/dotnet-architecture/eShopOnBlazor) - ![GitHub stars](https://img.shields.io/github/stars/dotnet-architecture/eShopOnBlazor?style=flat-square&cacheSeconds=604800&logo=microsoft) ![last commit](https://img.shields.io/github/last-commit/dotnet-architecture/eShopOnBlazor?style=flat-square&cacheSeconds=86400) Migration of a traditional ASP.NET Web Forms app to Blazor, sample by Microsoft Architecture. 35 | 36 | ## Sample Projects 37 | ### Authentication 38 | * [BlazorBoilerplate](https://github.com/enkodellc/blazorboilerplate) - ![stars](https://img.shields.io/github/stars/enkodellc/blazorboilerplate?style=flat-square&cacheSeconds=604800) ![last commit](https://img.shields.io/github/last-commit/enkodellc/blazorboilerplate?style=flat-square&cacheSeconds=86400) Real World Admin Dashboard / Starter kit with IdentityServer4 Material Design. [Demo](https://blazorboilerplate.com). 39 | 40 | ### Cloud 41 | * [BlazorAzure.WebApp](https://github.com/gpeipman/BlazorDemo/tree/master/BlazorAzure.WebApp) - ![stars](https://img.shields.io/github/stars/gpeipman/BlazorDemo?style=flat-square&cacheSeconds=604800) ![last commit](https://img.shields.io/github/last-commit/gpeipman/BlazorDemo?style=flat-square&cacheSeconds=86400) Blazor Azure web app. 42 | * [BlazorFile2Azure](https://github.com/daltskin/BlazorFile2Azure) - ![last commit](https://img.shields.io/github/last-commit/daltskin/BlazorFile2Azure?style=flat-square&cacheSeconds=86400) Upload a file from Blazor WebAssembly to Azure Blob Storage. 43 | 44 | ## Tutorials 45 | 46 | * [Blazor workshop](https://github.com/dotnet-presentations/blazor-workshop/) - ![GitHub stars](https://img.shields.io/github/stars/dotnet-presentations/blazor-workshop?style=flat-square&cacheSeconds=604800&logo=microsoft) Blazor app building workshop by [.NET Foundation](https://www.dotnetfoundation.org/), Blazzing Pizza. 47 | 48 | ## License 49 | * [![CC0](http://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg)](https://creativecommons.org/publicdomain/zero/1.0/) -------------------------------------------------------------------------------- /AwesomeBlazor.Models.Test/TestFixture.cs: -------------------------------------------------------------------------------- 1 | namespace AwesomeBlazor.Models.Test; 2 | 3 | internal static class TestFixture 4 | { 5 | public static string GetContentsForTest() 6 | { 7 | var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Sample.md"); 8 | var contents = File.ReadAllText(path); 9 | return contents; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models/AwesomeBlazor.Models.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net10.0 5 | enable 6 | $(WarningsAsErrors);nullable 7 | Latest 8 | true 9 | enable 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models/AwesomeBlazorParser.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using System.Text.RegularExpressions; 3 | using Markdig; 4 | 5 | namespace AwesomeBlazor.Models; 6 | 7 | public static class AwesomeBlazorParser 8 | { 9 | private enum LineTypes 10 | { 11 | Group, 12 | Paragraph, 13 | Resource 14 | } 15 | 16 | public static AwesomeResourceGroup ParseMarkdown(string markdownContents, AwesomeBlazorParserOptions? options = null) 17 | { 18 | options ??= new AwesomeBlazorParserOptions(); 19 | 20 | var currentGroup = default(AwesomeResourceGroup); 21 | var awsomeBlazorRoot = new AwesomeResourceGroup(); 22 | var groups = new[] { awsomeBlazorRoot }; 23 | 24 | var paragraphs = new List(); 25 | 26 | var prevLineType = LineTypes.Group; 27 | var lines = markdownContents.Split('\r', '\n'); 28 | foreach (var current in lines) 29 | { 30 | var groupMatch = Regex.Match(current, "^(?#+)[ ]*(?.+)$"); 31 | if (groupMatch.Success) 32 | { 33 | prevLineType = LineTypes.Group; 34 | var title = groupMatch.Groups["title"].Value; 35 | var level = Math.Max(1, groupMatch.Groups["level"].Value.Length - 1); 36 | if (groups.Length <= level) Array.Resize(ref groups, level + 1); 37 | 38 | if (title == options.EndCategoryName) break; 39 | 40 | if (currentGroup != null && paragraphs.Any(p => !string.IsNullOrEmpty(p))) 41 | { 42 | currentGroup.ParagraphsHtml = PostProcessHtml(Markdown.ToHtml(string.Join("\n", paragraphs)), stripParagraphTag: false); 43 | } 44 | paragraphs.Clear(); 45 | 46 | if (options.SkipCategoryNames.Contains(title)) 47 | { 48 | currentGroup = null; 49 | } 50 | else 51 | { 52 | var titleHtml = PostProcessHtml(Markdown.ToHtml(title), stripParagraphTag: true); 53 | currentGroup = new AwesomeResourceGroup(title: HtmlToText(titleHtml), titleHtml: titleHtml); 54 | groups[level - 1].SubGroups.Add(currentGroup); 55 | groups[level] = currentGroup; 56 | } 57 | } 58 | 59 | else if (currentGroup != null) 60 | { 61 | if (TryParseAsResource(current, out var resource)) 62 | { 63 | prevLineType = LineTypes.Resource; 64 | currentGroup.Resources.Add(resource); 65 | } 66 | else if (prevLineType == LineTypes.Resource && !string.IsNullOrEmpty(current)) 67 | { 68 | prevLineType = LineTypes.Resource; 69 | var descriptionHtml = PostProcessHtml(Markdown.ToHtml(current), stripParagraphTag: true); 70 | var descriptionText = HtmlToText(descriptionHtml); 71 | var lastResource = currentGroup.Resources.Last(); 72 | lastResource.DescriptionHtml += " " + descriptionHtml; 73 | lastResource.DescriptionText += " " + descriptionText; 74 | } 75 | else 76 | { 77 | prevLineType = LineTypes.Paragraph; 78 | paragraphs.Add(current); 79 | } 80 | } 81 | } 82 | 83 | return awsomeBlazorRoot; 84 | } 85 | 86 | private static string PostProcessHtml(string html, bool stripParagraphTag) 87 | { 88 | if (stripParagraphTag) 89 | { 90 | html = Regex.Replace(html, "</?p>", ""); 91 | } 92 | return Regex.Replace(html, "<a (?<prop>[^>]+)>", m => "<a " + m.Groups["prop"].Value + " target=\"_blank\">") 93 | .Trim(); 94 | } 95 | 96 | private static string HtmlToText(string html) 97 | { 98 | return Regex.Replace(html, "<[^>]+>", "") 99 | .Replace(""", "\"") 100 | .Replace("&", "&") 101 | .Trim(); 102 | } 103 | 104 | internal static bool TryParseAsResource(string contents, [NotNullWhen(true)] out AwesomeResource? resource) 105 | { 106 | resource = null; 107 | 108 | if (string.IsNullOrEmpty(contents)) return false; 109 | 110 | var m1 = Regex.Match(contents, @"^(\*[ ]+)?\[(?<title>[^]]+)\]\((?<url>[^)]+)\)[ ]+(\-[ ]+)?(?<body>.+)$"); 111 | if (!m1.Success) return false; 112 | 113 | var body = m1.Groups["body"].Value; 114 | var gitHubStarsUrl = ""; 115 | var lastCommitUrl = ""; 116 | body = Regex.Replace(body, @"\!\[[^]]+\]\((?<url>https://img.shields.io/github/(?<type>last-commit|stars)/[^)]+)\)", m => 117 | { 118 | if (m.Groups["type"].Value == "stars") 119 | gitHubStarsUrl = m.Groups["url"].Value; 120 | else 121 | lastCommitUrl = m.Groups["url"].Value; 122 | return ""; 123 | }); 124 | 125 | 126 | var descriptionHtml = PostProcessHtml(Markdown.ToHtml(body), stripParagraphTag: true); 127 | var descriptionText = HtmlToText(descriptionHtml); 128 | resource = new AwesomeResource( 129 | m1.Groups["title"].Value, 130 | m1.Groups["url"].Value, 131 | gitHubStarsUrl, 132 | lastCommitUrl, 133 | descriptionText, 134 | descriptionHtml 135 | ); 136 | return true; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models/AwesomeBlazorParserOptions.cs: -------------------------------------------------------------------------------- 1 | namespace AwesomeBlazor.Models; 2 | 3 | public class AwesomeBlazorParserOptions 4 | { 5 | public List<string> SkipCategoryNames { get; set; } = ["Contents"]; 6 | 7 | public string EndCategoryName { get; set; } = "License"; 8 | } 9 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models/AwesomeResource.cs: -------------------------------------------------------------------------------- 1 | namespace AwesomeBlazor.Models; 2 | 3 | public class AwesomeResource 4 | { 5 | public Guid Id { get; } = Guid.NewGuid(); 6 | 7 | public bool Visible { get; set; } = true; 8 | 9 | public string Title { get; } 10 | 11 | public string ResourceUrl { get; } 12 | 13 | public string GitHubStarsUrl { get; } 14 | 15 | public string LastCommitUrl { get; } 16 | 17 | public string DescriptionText { get; set; } 18 | 19 | public string DescriptionHtml { get; set; } 20 | 21 | public AwesomeResource(string title, string resourceUrl, string gitHubStarsUrl, string lastCommitUrl, string descriptionText, string descriptionHtml) 22 | { 23 | this.Title = title; 24 | this.ResourceUrl = resourceUrl; 25 | this.GitHubStarsUrl = gitHubStarsUrl; 26 | this.LastCommitUrl = lastCommitUrl; 27 | this.DescriptionText = descriptionText; 28 | this.DescriptionHtml = descriptionHtml; 29 | } 30 | 31 | public override string ToString() 32 | { 33 | return $"{this.Title}"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models/AwesomeResourceFilter.cs: -------------------------------------------------------------------------------- 1 | namespace AwesomeBlazor.Models; 2 | 3 | public static class AwesomeResourceFilter 4 | { 5 | public static void UpdateVisibiltyByKeywordFilter(this IEnumerable<AwesomeResourceGroup> groups, string keywords) 6 | { 7 | var keywordsArray = string.IsNullOrEmpty(keywords) ? 8 | [] : 9 | keywords.ToLower().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); 10 | 11 | groups.UpdateVisibiltyByKeywordFilter(keywordsArray); 12 | } 13 | 14 | private static void UpdateVisibiltyByKeywordFilter(this IEnumerable<AwesomeResourceGroup> groups, string[] keywords) 15 | { 16 | foreach (var group in groups) 17 | { 18 | group.UpdateVisibiltyByKeywordFilter(keywords); 19 | } 20 | } 21 | 22 | private static void UpdateVisibiltyByKeywordFilter(this AwesomeResourceGroup group, string[] keywords) 23 | { 24 | group.Visible = group.SelectionState != SelectionState.Unselected; 25 | if (group.Visible) 26 | { 27 | foreach (var resource in group.Resources) 28 | { 29 | resource.Visible = keywords.All(keyword => 30 | resource.Title.ToLower().Contains(keyword) || 31 | resource.DescriptionText.ToLower().Contains(keyword) || 32 | group.Title.ToLower().Contains(keyword)); 33 | } 34 | 35 | group.SubGroups.UpdateVisibiltyByKeywordFilter(keywords); 36 | 37 | group.Visible = 38 | (group.ParagraphsHtml != "" && !keywords.Any()) || 39 | group.Resources.Any(r => r.Visible) || 40 | group.SubGroups.Any(g => g.Visible); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models/AwesomeResourceGroup.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace AwesomeBlazor.Models; 4 | 5 | public class AwesomeResourceGroup 6 | { 7 | public Guid Id { get; } = Guid.NewGuid(); 8 | 9 | private bool Selected = true; 10 | 11 | public SelectionState SelectionState 12 | { 13 | get 14 | { 15 | if (!this.SubGroups.Any()) return this.Selected ? SelectionState.Selected : SelectionState.Unselected; 16 | if (this.SubGroups.All(g => g.SelectionState == SelectionState.Unselected)) return SelectionState.Unselected; 17 | if (this.SubGroups.All(g => g.SelectionState == SelectionState.Selected)) return SelectionState.Selected; 18 | return SelectionState.SelectedAny; 19 | } 20 | set 21 | { 22 | if (!this.SubGroups.Any()) this.Selected = value == SelectionState.Selected; 23 | foreach (var subGropup in this.SubGroups) 24 | { 25 | subGropup.SelectionState = value; 26 | } 27 | } 28 | } 29 | 30 | public bool Visible { get; set; } = true; 31 | 32 | public bool Expanded { get; set; } = true; 33 | 34 | public string Title { get; } 35 | 36 | public string TitleHtml { get; } 37 | 38 | public List<AwesomeResourceGroup> SubGroups { get; } = []; 39 | 40 | public List<AwesomeResource> Resources { get; } = []; 41 | 42 | public string ParagraphsHtml { get; set; } = ""; 43 | 44 | private readonly string AnchorName; 45 | 46 | public AwesomeResourceGroup() : this(title: "", titleHtml: "") 47 | { 48 | } 49 | 50 | public AwesomeResourceGroup(string title, string titleHtml) 51 | { 52 | this.Title = title; 53 | this.TitleHtml = titleHtml; 54 | this.AnchorName = Regex.Replace(title, "[^a-zA-Z0-9]", "-").ToLower(); 55 | } 56 | 57 | public override string ToString() 58 | { 59 | return $"{this.Title}"; 60 | } 61 | 62 | public string GetAnchorName(string prefix = "") 63 | { 64 | if (prefix == "") return this.AnchorName; 65 | else return prefix + "-" + this.AnchorName; 66 | } 67 | 68 | public int GetExpandedDescendantsCount() 69 | { 70 | if (this.Expanded == false) return 0; 71 | var childrenCount = this.SubGroups.Count; 72 | var descendantsCount = this.SubGroups.Select(subGrp => subGrp.GetExpandedDescendantsCount()).Sum(); 73 | return childrenCount + descendantsCount; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models/AwesomeResourceGroupsExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace AwesomeBlazor.Models; 2 | 3 | public static class AwesomeResourceGroupsExtensions 4 | { 5 | public static IEnumerable<AwesomeResourceGroup> EnumGroupsDescendants(this IEnumerable<AwesomeResourceGroup> groups) 6 | { 7 | foreach (var group in groups) 8 | { 9 | yield return group; 10 | foreach (var subGroup in group.SubGroups.EnumGroupsDescendants()) 11 | { 12 | yield return subGroup; 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AwesomeBlazor.Models/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("AwesomeBlazor.Models.Test")] -------------------------------------------------------------------------------- /AwesomeBlazor.Models/SelectionState.cs: -------------------------------------------------------------------------------- 1 | namespace AwesomeBlazor.Models; 2 | 3 | public enum SelectionState 4 | { 5 | Unselected, 6 | SelectedAny, 7 | Selected 8 | } 9 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser.slnx: -------------------------------------------------------------------------------- 1 | <Solution> 2 | <Folder Name="/README/"> 3 | <File Path="LICENSE" /> 4 | <File Path="README.md" /> 5 | <File Path="THIRD-PARTY-NOTICES.txt" /> 6 | </Folder> 7 | <Folder Name="/Solution Items/"> 8 | <File Path=".editorconfig" /> 9 | <File Path=".github/workflows/gh-pages.yml" /> 10 | </Folder> 11 | <Project Path="AwesomeBlazor.Models.Test/AwesomeBlazor.Models.Test.csproj" /> 12 | <Project Path="AwesomeBlazor.Models/AwesomeBlazor.Models.csproj" /> 13 | <Project Path="AwesomeBlazorBrowser/AwesomeBlazorBrowser.csproj" /> 14 | </Solution> 15 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to find out which attributes exist for C# debugging 3 | // Use hover for the description of the existing attributes 4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Core Launch (web)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "dotnet", 14 | "args": [ 15 | "run" 16 | ], 17 | "cwd": "${workspaceFolder}", 18 | "stopAtEntry": false, 19 | // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser 20 | "serverReadyAction": { 21 | "action": "openExternally", 22 | "pattern": "^\\s*Now listening on:\\s+(https?://\\S+)" 23 | }, 24 | "env": { 25 | "ASPNETCORE_ENVIRONMENT": "Development" 26 | } 27 | }, 28 | { 29 | "name": ".NET Core Attach", 30 | "type": "coreclr", 31 | "request": "attach", 32 | "processId": "${command:pickProcess}" 33 | } 34 | ] 35 | } -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "group": { 9 | "kind": "build", 10 | "isDefault": true 11 | }, 12 | "args": [ 13 | "build", 14 | "${workspaceFolder}/AwesomeBlazorBrowser.csproj", 15 | "/property:GenerateFullPaths=true", 16 | "/consoleloggerparameters:NoSummary" 17 | ], 18 | "problemMatcher": "$msCompile" 19 | }, 20 | { 21 | "label": "publish", 22 | "command": "dotnet", 23 | "type": "process", 24 | "args": [ 25 | "publish", 26 | "${workspaceFolder}/AwesomeBlazorBrowser.csproj", 27 | "/property:GenerateFullPaths=true", 28 | "/consoleloggerparameters:NoSummary" 29 | ], 30 | "problemMatcher": "$msCompile" 31 | }, 32 | { 33 | "label": "watch", 34 | "command": "dotnet", 35 | "type": "process", 36 | "args": [ 37 | "watch", 38 | "run", 39 | "${workspaceFolder}/AwesomeBlazorBrowser.csproj", 40 | "/property:GenerateFullPaths=true", 41 | "/consoleloggerparameters:NoSummary" 42 | ], 43 | "problemMatcher": "$msCompile" 44 | } 45 | ] 46 | } -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/App.razor: -------------------------------------------------------------------------------- 1 | <div class="header-pane"> 2 | <AppBar EnableSearchBox="@(!Loading)" 3 | OnChangeKeywords="OnChangeKeywords" 4 | OnClickGroupPanelMenu="OnClickGroupPanelMenu" 5 | OnClickSettings="OnClickSettings" /> 6 | </div> 7 | 8 | @if (this.Loading) 9 | { 10 | <div class="loading-mask"> 11 | <div class="loading">Loading...</div> 12 | <link rel="stylesheet" 13 | href="data:text/css,.loading%7Bfont-family%3A'Franklin%20Gothic%20Medium'%2C'Arial%20Narrow'%2CArial%2Csans-serif%3Bcolor%3A%2388a%3Bfont-size%3A18px%3Btext-align%3Acenter%3Bwidth%3A150px%3Bheight%3A150px%3Bposition%3Afixed%3Btop%3A0%3Bbottom%3A0%3Bleft%3A0%3Bright%3A0%3Bmargin%3Aauto%7D.loading%3A%3Aafter%7Bcontent%3A''%3Bborder%3Asolid%2010px%3Bborder-color%3A%2388a%20%23eee%20%23eee%3Bborder-radius%3A60px%3Bposition%3Aabsolute%3Bwidth%3A60px%3Bheight%3A60px%3Btop%3A0%3Bbottom%3A0%3Bleft%3A0%3Bright%3A0%3Bmargin%3Aauto%3Banimation%3Arotation%201.5s%20linear%200s%20infinite%7D%40keyframes%20rotation%7B0%25%7Btransform%3Arotate(45deg)%7D100%25%7Btransform%3Arotate(405deg)%7D%7D" /> 14 | </div> 15 | } 16 | 17 | <div class="left-pane @CssClass(new{GroupPanelExpanded})"> 18 | <GroupsPanel Group="RootGroup" OnChangeGroupState="OnChangeGroupState" OnClickGroupLink="OnClickGroupLink" /> 19 | </div> 20 | 21 | <div class="right-pane @CssClass(new{SettingsPanelExpanded})"> 22 | <Settings /> 23 | </div> 24 | 25 | <div class="main"> 26 | <Contents Groups="RootGroup.SubGroups" /> 27 | </div> 28 | 29 | <div class="main-mask @CssClass(new{GroupPanelExpanded, SettingsPanelExpanded})" @onclick="OnClickMainMask"> 30 | </div> 31 | 32 | <div class="footer-pane"> 33 | <Footer /> 34 | </div> 35 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/App.razor.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using AwesomeBlazor.Models; 3 | using Microsoft.AspNetCore.Components; 4 | 5 | namespace AwesomeBlazorBrowser; 6 | 7 | public partial class App 8 | { 9 | [Inject] HttpClient HttpClient { get; init; } = null!; 10 | 11 | [Inject] NavigationManager NavigationManager { get; init; } = null!; 12 | 13 | [Inject] public HelperScriptService HelperScript { get; init; } = null!; 14 | 15 | private AwesomeResourceGroup RootGroup = new(); 16 | 17 | private string Keywords = ""; 18 | 19 | private bool Loading = true; 20 | 21 | private bool GroupPanelExpanded = false; 22 | 23 | private bool SettingsPanelExpanded = false; 24 | 25 | private readonly TaskCompletionSource ParsingCompletionSource = new(); 26 | 27 | protected override async Task OnInitializedAsync() 28 | { 29 | var url = "https://raw.githubusercontent.com/AdrienTorris/awesome-blazor/master/README.md"; 30 | var awesomeBlazorContents = await this.HttpClient.GetStringAsync(url); 31 | this.RootGroup = AwesomeBlazorParser.ParseMarkdown(awesomeBlazorContents); 32 | this.ParsingCompletionSource.SetResult(); 33 | } 34 | 35 | protected override async Task OnAfterRenderAsync(bool firstRender) 36 | { 37 | if (firstRender) await this.HelperScript.InstallHashWatcherAsync(); 38 | 39 | if (this.ParsingCompletionSource.Task.IsCompleted == true && this.Loading == true) 40 | { 41 | this.Loading = false; 42 | this.StateHasChanged(); 43 | 44 | var uriFragment = new Uri(this.NavigationManager.Uri).Fragment; 45 | if (uriFragment != "") 46 | { 47 | await this.HelperScript.ScrollToAnchorAsync(uriFragment, smooth: false); 48 | } 49 | } 50 | } 51 | 52 | private void UpdateRootGroupVisibility() 53 | { 54 | this.RootGroup.SubGroups.UpdateVisibiltyByKeywordFilter(this.Keywords); 55 | } 56 | 57 | private void OnChangeGroupState() 58 | { 59 | this.UpdateRootGroupVisibility(); 60 | } 61 | 62 | private async Task OnChangeKeywords(string keywords) 63 | { 64 | this.Keywords = keywords; 65 | 66 | await this.ParsingCompletionSource.Task; 67 | 68 | this.UpdateRootGroupVisibility(); 69 | 70 | var uri = new Uri(this.NavigationManager.Uri); 71 | var queryStrings = HttpUtility.ParseQueryString(uri.Query); 72 | queryStrings["k"] = keywords; 73 | var nextUrl = new UriBuilder(uri) { Query = queryStrings.ToString() }.Uri.ToString(); 74 | this.NavigationManager.NavigateTo(nextUrl, new NavigationOptions() { ReplaceHistoryEntry = true }); 75 | 76 | this.GroupPanelExpanded = false; 77 | this.SettingsPanelExpanded = false; 78 | } 79 | 80 | private void OnClickGroupPanelMenu() 81 | { 82 | this.GroupPanelExpanded = !this.GroupPanelExpanded; 83 | this.SettingsPanelExpanded = false; 84 | } 85 | 86 | private void OnClickSettings() 87 | { 88 | this.SettingsPanelExpanded = !this.SettingsPanelExpanded; 89 | this.GroupPanelExpanded = false; 90 | } 91 | 92 | private void OnClickGroupLink() 93 | { 94 | this.GroupPanelExpanded = false; 95 | } 96 | 97 | private void OnClickMainMask() 98 | { 99 | this.GroupPanelExpanded = false; 100 | this.SettingsPanelExpanded = false; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/App.razor.scss: -------------------------------------------------------------------------------- 1 | @import "site.mixin.scss"; 2 | @import "site.variables.scss"; 3 | 4 | $app-bar-height: 72px; 5 | $app-bar-height-large: 100px; 6 | $left-pane-width: 280px; 7 | $right-pane-width: 180px; 8 | $footer-height: 38px; 9 | 10 | #app { 11 | display: block; 12 | position: fixed; 13 | top: 0; 14 | left: 0; 15 | bottom: 0; 16 | right: 0; 17 | padding: 10px; 18 | background-color: var(--default-back-color); 19 | 20 | & > .header-pane { 21 | position: absolute; 22 | top: 0; 23 | left: 0; 24 | right: 0; 25 | height: $app-bar-height; 26 | } 27 | 28 | & > .loading-mask { 29 | position: absolute; 30 | top: $app-bar-height; 31 | left: 0; 32 | bottom: $footer-height; 33 | right: 0; 34 | z-index: 3; 35 | background-color: var(--default-back-color); 36 | } 37 | 38 | & > .left-pane { 39 | border-right: solid 1px var(--default-border-color); 40 | display: block; 41 | position: absolute; 42 | top: $app-bar-height; 43 | left: 0; 44 | bottom: $footer-height; 45 | width: $left-pane-width; 46 | transition: left ease 0.2s; 47 | z-index: 1; 48 | background-color: var(--default-back-color); 49 | } 50 | 51 | & > .right-pane { 52 | border-left: solid 1px var(--default-border-color); 53 | display: block; 54 | position: absolute; 55 | top: $app-bar-height; 56 | right: -1 * $right-pane-width - 1; 57 | bottom: $footer-height; 58 | width: $right-pane-width; 59 | transition: right ease 0.2s; 60 | z-index: 2; 61 | background-color: var(--default-back-color); 62 | 63 | &.settings-panel-expanded { 64 | right: 0; 65 | } 66 | } 67 | 68 | & > .main-mask { 69 | display: block; 70 | position: absolute; 71 | top: $app-bar-height; 72 | bottom: $footer-height; 73 | left: 0; 74 | right: 0; 75 | z-index: 1; 76 | background-color: #000; 77 | pointer-events: none; 78 | opacity: 0; 79 | transition: opacity ease 0.2s; 80 | 81 | &.settings-panel-expanded { 82 | opacity: 0.5; 83 | pointer-events: all; 84 | } 85 | } 86 | 87 | & > .main { 88 | display: block; 89 | position: absolute; 90 | top: $app-bar-height; 91 | left: $left-pane-width; 92 | bottom: $footer-height; 93 | right: 0; 94 | overflow-x: hidden; 95 | overflow-y: scroll; 96 | transition: left ease 0.2s; 97 | 98 | @include scrollbar-color(var(--scrollbar-thumb-color), var(--scrollbar-back-color)); 99 | } 100 | 101 | & > .footer-pane { 102 | border-top: solid 1px var(--default-border-color); 103 | position: absolute; 104 | left: 0; 105 | right: 0; 106 | bottom: 0; 107 | height: $footer-height; 108 | } 109 | 110 | @media (max-width: $breakpoints-sm) { 111 | & > .header-pane { 112 | height: $app-bar-height-large; 113 | } 114 | 115 | & > .left-pane { 116 | top: $app-bar-height-large; 117 | left: -1 * $left-pane-width - 1; 118 | z-index: 2; 119 | 120 | &.group-panel-expanded { 121 | left: 0; 122 | } 123 | } 124 | 125 | & > .right-pane { 126 | top: $app-bar-height-large; 127 | } 128 | 129 | & > .main-mask { 130 | top: $app-bar-height-large; 131 | 132 | &.group-panel-expanded { 133 | opacity: 0.5; 134 | pointer-events: all; 135 | } 136 | } 137 | 138 | & > .main { 139 | top: $app-bar-height-large; 140 | left: 0; 141 | } 142 | 143 | & > .loading-mask { 144 | top: $app-bar-height-large; 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/AwesomeBlazorBrowser.csproj: -------------------------------------------------------------------------------- 1 | <Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly"> 2 | 3 | <PropertyGroup> 4 | <TargetFramework>net10.0</TargetFramework> 5 | <ImplicitUsings>enable</ImplicitUsings> 6 | <Nullable>enable</Nullable> 7 | <WarningsAsErrors>$*WarningsAsErrors);nullable</WarningsAsErrors> 8 | <InvariantGlobalization>true</InvariantGlobalization> 9 | <BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport> 10 | <OverrideHtmlAssetPlaceholders>true</OverrideHtmlAssetPlaceholders> 11 | </PropertyGroup> 12 | 13 | <ItemGroup> 14 | <Content Remove="compilerconfig.json" /> 15 | <None Include="compilerconfig.json" /> 16 | </ItemGroup> 17 | 18 | <ItemGroup> 19 | <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.0-preview.5.*" /> 20 | <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.0-preview.5.*" PrivateAssets="all" /> 21 | <PackageReference Include="PublishSPAforGitHubPages.Build" Version="3.0.0" /> 22 | <PackageReference Include="BlazorWasmPreRendering.Build" Version="6.0.0-preview.2" /> 23 | <PackageReference Include="Toolbelt.Web.CssClassInlineBuilder" Version="3.1.0.1" /> 24 | <!--<PackageReference Include="Toolbelt.Blazor.GradatedText" Version="1.0.0" />--> 25 | </ItemGroup> 26 | 27 | <ItemGroup> 28 | <PackageReference Include="Microsoft.TypeScript.MSBuild" Version="4.8.4"> 29 | <PrivateAssets>all</PrivateAssets> 30 | <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> 31 | </PackageReference> 32 | </ItemGroup> 33 | 34 | <ItemGroup> 35 | <ProjectReference Include="..\AwesomeBlazor.Models\AwesomeBlazor.Models.csproj" /> 36 | </ItemGroup> 37 | 38 | <PropertyGroup> 39 | <TypeScriptTarget>ES2016</TypeScriptTarget> 40 | <TypeScriptJSXEmit>None</TypeScriptJSXEmit> 41 | <TypeScriptModuleKind>ES2015</TypeScriptModuleKind> 42 | <TypeScriptCompileOnSaveEnabled>True</TypeScriptCompileOnSaveEnabled> 43 | <TypeScriptNoImplicitAny>True</TypeScriptNoImplicitAny> 44 | <TypeScriptRemoveComments>True</TypeScriptRemoveComments> 45 | <TypeScriptOutFile /> 46 | <TypeScriptOutDir>wwwroot/scripts</TypeScriptOutDir> 47 | <TypeScriptGeneratesDeclarations>False</TypeScriptGeneratesDeclarations> 48 | <TypeScriptNoEmitOnError>True</TypeScriptNoEmitOnError> 49 | <TypeScriptSourceMap>True</TypeScriptSourceMap> 50 | <TypeScriptMapRoot /> 51 | <TypeScriptSourceRoot /> 52 | </PropertyGroup> 53 | 54 | </Project> -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/AppBar.razor: -------------------------------------------------------------------------------- 1 | <div class="app-bar"> 2 | <div class="app-text"> 3 | <span class="app-icon"> 4 | @* <GradatedText> *@ 5 |  6 | @* </GradatedText> *@ 7 | </span> 8 | <div class="app-title"> 9 | @* <GradatedText> *@ 10 | Awesome Blazor Browser 11 | @* </GradatedText> *@ 12 | </div> 13 | <div class="app-description"> 14 | This is a browser for 15 | <a href="https://github.com/AdrienTorris/awesome-blazor" target="_blank">"Awesome Blazor"</a>.<br /> 16 | Special thanks to contributor's great works! 17 | </div> 18 | </div> 19 | 20 | <div class="search-box @CssClass(new{EnableSearchBox})"> 21 | <a class="icon icon-menu" @onclick="@(()=> this.OnClickGroupPanelMenu.InvokeAsync())"></a> 22 | <input type="text" placeholder="Search" @bind-value="Keywords" @oninput="OnInputKeywords" /> 23 | <a class="icon icon-settings" @onclick="@(()=> this.OnClickSettings.InvokeAsync())"></a> 24 | </div> 25 | </div> 26 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/AppBar.razor.cs: -------------------------------------------------------------------------------- 1 | using System.Timers; 2 | using System.Web; 3 | using Microsoft.AspNetCore.Components; 4 | 5 | namespace AwesomeBlazorBrowser.Components; 6 | 7 | public partial class AppBar : IDisposable 8 | { 9 | private string Keywords = ""; 10 | 11 | private readonly System.Timers.Timer DebounceTimer = new System.Timers.Timer(interval: 500) { AutoReset = false }; 12 | 13 | [Inject] public NavigationManager NavigationManager { get; init; } = null!; 14 | 15 | [Parameter] public bool EnableSearchBox { get; set; } 16 | 17 | [Parameter] public EventCallback<string> OnChangeKeywords { get; set; } 18 | 19 | [Parameter] public EventCallback OnClickGroupPanelMenu { get; set; } 20 | 21 | [Parameter] public EventCallback OnClickSettings { get; set; } 22 | 23 | protected override void OnInitialized() 24 | { 25 | this.DebounceTimer.Elapsed += this.DebounceTimer_Elapsed; 26 | } 27 | 28 | protected override void OnAfterRender(bool firstRender) 29 | { 30 | if (firstRender) 31 | { 32 | var uri = new Uri(this.NavigationManager.Uri); 33 | var queryStrings = HttpUtility.ParseQueryString(uri.Query); 34 | var keyword = queryStrings["k"] ?? ""; 35 | if (keyword != this.Keywords) 36 | { 37 | this.Keywords = keyword; 38 | this.OnChangeKeywords.InvokeAsync(this.Keywords); 39 | } 40 | } 41 | } 42 | 43 | private void OnInputKeywords(ChangeEventArgs args) 44 | { 45 | this.Keywords = args.Value?.ToString() ?? ""; 46 | this.DebounceTimer.Stop(); 47 | this.DebounceTimer.Start(); 48 | } 49 | 50 | private void DebounceTimer_Elapsed(object? sender, ElapsedEventArgs e) 51 | { 52 | this.OnChangeKeywords.InvokeAsync(this.Keywords); 53 | } 54 | 55 | public void Dispose() 56 | { 57 | this.DebounceTimer.Elapsed -= this.DebounceTimer_Elapsed; 58 | this.DebounceTimer.Dispose(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/AppBar.razor.scss: -------------------------------------------------------------------------------- 1 | @import "../icons.variables.scss"; 2 | @import "../site.variables.scss"; 3 | 4 | .app-bar { 5 | background-color: var(--appbar-back-color); 6 | color: var(--appbar-text-color); 7 | position: absolute; 8 | top: 0; 9 | left: 0; 10 | bottom: 0; 11 | right: 0; 12 | display: flex; 13 | justify-content: left; 14 | align-items: center; 15 | 16 | & > .app-text { 17 | position: relative; 18 | margin-left: 16px; 19 | padding-left: 46px; 20 | 21 | .app-icon { 22 | font-family: '#{$icomoon-font-family}'; 23 | font-size: 32px; 24 | position: absolute; 25 | top: -2px; 26 | left: 0; 27 | } 28 | 29 | min-width: 280px; 30 | 31 | a { 32 | color: #86bfff; 33 | } 34 | 35 | & > .app-title { 36 | font-weight: 600; 37 | font-size: 18px; 38 | } 39 | 40 | & > .app-description { 41 | font-size: 12px; 42 | color: var(--weaked-text-color); 43 | line-height: 14px; 44 | } 45 | } 46 | 47 | & > .search-box { 48 | margin-left: 16px; 49 | margin-right: 16px; 50 | flex-grow: 1; 51 | display: flex; 52 | align-items: center; 53 | visibility: hidden; 54 | 55 | &.enable-search-box { 56 | visibility: visible; 57 | } 58 | 59 | .icon-menu, .icon-settings { 60 | color: var(--appbar-text-color); 61 | text-decoration: none; 62 | font-size: 24px; 63 | padding: 8px; 64 | transition: color ease 0.2s; 65 | 66 | &:hover { 67 | color: #fff; 68 | } 69 | } 70 | 71 | .icon-menu { 72 | display: none; 73 | } 74 | 75 | input { 76 | background-color: var(--searchbox-back-color); 77 | flex-grow: 1; 78 | border: solid 1px var(--searchbox-border-color); 79 | height: 28px; 80 | padding-left: 10px; 81 | border-radius: 4px; 82 | color: var(--searchbox-text-color); 83 | outline: none; 84 | 85 | &:focus { 86 | background-color: var(--searchbox-back-color-focused); 87 | color: var(--searchbox-text-color-focused); 88 | } 89 | } 90 | } 91 | 92 | @media (max-width: $breakpoints-sm) { 93 | flex-direction: column; 94 | justify-content: center; 95 | 96 | & > .app-text { 97 | & > .app-description { 98 | font-size: 12px; 99 | line-height: 12px; 100 | } 101 | } 102 | 103 | & > .search-box { 104 | width: 100%; 105 | flex-grow: 0; 106 | margin-top: 6px; 107 | 108 | .icon-menu { 109 | display: inline-block; 110 | } 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/Contents.razor: -------------------------------------------------------------------------------- 1 | <div class="awesome-blazor-contents"> 2 | @foreach (var group in Groups) 3 | { 4 | var anchorName = group.GetAnchorName(this.ParentGroupAnchor); 5 | 6 | <div class="@CssClass("group", new { group.Visible })" @key="group.Id"> 7 | 8 | <div class="group-title"> 9 | <a class="group-anchor" name="@anchorName" href="#@(anchorName)" @onclick="@(() => OnClickGroupLink(anchorName))" @onclick:preventDefault="true"></a> 10 | @((MarkupString)group.TitleHtml) 11 | </div> 12 | 13 | @if (!string.IsNullOrEmpty(group.ParagraphsHtml)) 14 | { 15 | <div class="paragraphs"> 16 | @((MarkupString)group.ParagraphsHtml) 17 | </div> 18 | } 19 | 20 | <div class="resources"> 21 | @foreach (var resource in group.Resources.Where(res => res != null)) 22 | { 23 | <div class="@CssClass("resource", new { resource.Visible })" @key="resource.Id"> 24 | <div class="resource-title"> 25 | <a href="@resource.ResourceUrl" target="_blank"> 26 | @resource.Title 27 | </a> 28 | </div> 29 | <div class="@CssClass("badges", new {HasBadges = HasBadges(resource) })"> 30 | @if (resource.GitHubStarsUrl != "") 31 | { 32 | <img src="@resource.GitHubStarsUrl" alt="GitHub Stars" class="badge github-stars" /> 33 | } 34 | @if (resource.LastCommitUrl != "") 35 | { 36 | <img src="@resource.LastCommitUrl" alt="Last Commit" class="badge last-commit" /> 37 | } 38 | </div> 39 | <div class="resource-description"> 40 | @((MarkupString)resource.DescriptionHtml) 41 | </div> 42 | </div> 43 | } 44 | </div> 45 | 46 | @if (group.SubGroups.Any()) 47 | { 48 | <div class="sub-groups"> 49 | <Contents ParentGroupAnchor="@anchorName" Groups="group.SubGroups" /> 50 | </div> 51 | } 52 | </div> 53 | } 54 | </div> -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/Contents.razor.cs: -------------------------------------------------------------------------------- 1 | using AwesomeBlazor.Models; 2 | using Microsoft.AspNetCore.Components; 3 | 4 | namespace AwesomeBlazorBrowser.Components; 5 | 6 | public partial class Contents 7 | { 8 | [Inject] public HelperScriptService HelperScript { get; init; } = null!; 9 | 10 | [Parameter] 11 | public string ParentGroupAnchor { get; set; } = ""; 12 | 13 | [Parameter] 14 | public IEnumerable<AwesomeResourceGroup> Groups { get; set; } = Enumerable.Empty<AwesomeResourceGroup>(); 15 | 16 | private bool HasBadges(AwesomeResource resource) 17 | { 18 | return resource.GitHubStarsUrl != "" || resource.LastCommitUrl != ""; 19 | } 20 | 21 | private async Task OnClickGroupLink(string anchorName) 22 | { 23 | await this.HelperScript.ScrollToAnchorAsync(anchorName, smooth: true, changeUrl: true); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/Contents.razor.scss: -------------------------------------------------------------------------------- 1 | @import "../icons.variables.scss"; 2 | 3 | .awesome-blazor-contents { 4 | margin-top: -20px; 5 | padding: 12px 12px 12px 32px; 6 | max-width: 900px; 7 | 8 | & > .group { 9 | display: none; 10 | 11 | &.visible { 12 | display: block; 13 | } 14 | 15 | & > .group-title { 16 | position: relative; 17 | font-size: 1.5em; 18 | font-weight: 600; 19 | color: var(--default-text-color); 20 | margin-top: 24px; 21 | margin-bottom: 16px; 22 | line-height: 1.25; 23 | padding-bottom: .3em; 24 | border-bottom: 1px solid var(--header-text-line-color); 25 | 26 | & > .group-anchor { 27 | position: absolute; 28 | width: 22px; 29 | height: 1.5em; 30 | left: -24px; 31 | display: flex; 32 | align-items: center; 33 | text-decoration: none; 34 | 35 | &:after { 36 | font-family: '#{$icomoon-font-family}'; 37 | content: $icon-link; 38 | font-size: 16px; 39 | color: var(--default-text-color); 40 | visibility: hidden; 41 | } 42 | } 43 | 44 | &:hover > .group-anchor:after { 45 | visibility: visible; 46 | } 47 | } 48 | 49 | blockquote { 50 | padding: 0 1em; 51 | color: var(--quote-text-color); 52 | border-left: .25em solid var(--quote-text-line-color); 53 | margin: 0 0 16px 0; 54 | } 55 | 56 | & > .resources { 57 | margin-left: 10px; 58 | 59 | & > .resource { 60 | margin-bottom: 10px; 61 | display: none; 62 | 63 | &.visible { 64 | display: block; 65 | } 66 | 67 | & > .resource-title { 68 | font-weight: 600; 69 | } 70 | 71 | & > .resource-description { 72 | margin-left: 10px; 73 | } 74 | 75 | & > .badges.has-badges { 76 | margin-top: 6px; 77 | margin-left: 10px; 78 | height: 24px; 79 | position: relative; 80 | 81 | & > .badge.last-commit { 82 | position: absolute; 83 | top: 0; 84 | left: 92px; 85 | } 86 | } 87 | 88 | & > .resource-description { 89 | img { 90 | vertical-align: middle; 91 | } 92 | } 93 | 94 | code { 95 | font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace; 96 | padding: .2em .4em; 97 | margin: 0; 98 | font-size: 85%; 99 | background-color: rgba(27,31,35,.05); 100 | border-radius: 3px; 101 | } 102 | } 103 | } 104 | 105 | & > .sub-groups > .awesome-blazor-contents { 106 | padding-left: 0; 107 | 108 | & > .group > .group-title { 109 | font-size: 1.25em; 110 | margin-top: 24px; 111 | margin-bottom: 16px; 112 | line-height: 1.25; 113 | padding-bottom: 0; 114 | border-bottom: none; 115 | } 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/Footer.razor: -------------------------------------------------------------------------------- 1 | <footer> 2 | 3 | <div class="footer-item blazor"> 4 | Powered by <a href="https://blazor.net" target="_blank">Blazor WebAssembly</a> 5 | @System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription 6 | </div> 7 | 8 | <div class="footer-item github"> 9 | Source Code is on <a href="https://github.com/jsakamoto/awesome-blazor-browser" target="_blank">GitHub</a> 10 | </div> 11 | 12 | </footer> -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/Footer.razor.scss: -------------------------------------------------------------------------------- 1 | @import "../icons.variables.scss"; 2 | 3 | footer { 4 | background-color: var(--footer-back-color); 5 | padding: 0 20px; 6 | overflow: hidden; 7 | position: absolute; 8 | top: 0; 9 | left: 0; 10 | bottom: 0; 11 | right: 0; 12 | font-size: 13px; 13 | display: flex; 14 | align-items: center; 15 | justify-content: flex-end; 16 | 17 | & > .footer-item { 18 | position: relative; 19 | margin-right: 20px; 20 | color: var(--footer-text-color); 21 | height: 24px; 22 | line-height: 24px; 23 | white-space: nowrap; 24 | 25 | &.blazor { 26 | &:after { 27 | font-family: '#{$icomoon-font-family}'; 28 | content: $icon-logo-blazor-large; 29 | font-size: 20px; 30 | position: absolute; 31 | top: 0; 32 | left: 0; 33 | } 34 | 35 | padding-left: 24px; 36 | } 37 | 38 | &.github { 39 | &:after { 40 | font-family: '#{$icomoon-font-family}'; 41 | content: $icon-mark-github; 42 | font-size: 20px; 43 | position: absolute; 44 | top: 0; 45 | left: 0; 46 | } 47 | 48 | padding-left: 24px; 49 | } 50 | } 51 | 52 | @media (max-width: 480px) { 53 | padding: 0 8px; 54 | font-size: 11.2px; 55 | 56 | & > .footer-item { 57 | margin-right: 8px; 58 | 59 | &:last-child { 60 | margin-right: 0; 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/GroupSelector.razor: -------------------------------------------------------------------------------- 1 | <div class="group-selector"> 2 | @foreach (var group in Groups) 3 | { 4 | var hasSubGroup = group.SubGroups.Any(); 5 | var anchorName = group.GetAnchorName(ParentGroupAnchor); 6 | 7 | <div class="@CssClass("group", new { group.Expanded, group.Visible })"> 8 | 9 | <div class="group-title"> 10 | 11 | <label class="@CssClass("toggle-box", group.SelectionState)"> 12 | <input type="button" @onclick="@(() => OnClickToggleBox(group))" /> 13 | </label> 14 | 15 | <a href="#@anchorName" class="link" @onclick="@(() => _OnClickGroupLink(anchorName))" @onclick:preventDefault="true"> 16 | @group.Title 17 | </a> 18 | 19 | @if (hasSubGroup) 20 | { 21 | <a class="icon expand-box" @onclick="@(() => OnClickExpandBox(group))"> 22 | </a> 23 | } 24 | </div> 25 | 26 | @if (hasSubGroup) 27 | { 28 | <div class="sub-group" style="height:@GetSubGroupsHeight(group);"> 29 | <GroupSelector ParentGroupAnchor="@anchorName" 30 | Groups="group.SubGroups" 31 | OnChangeGroupState="_OnChangeSubGroupState" 32 | OnClickGroupLink="@(()=> OnClickGroupLink.InvokeAsync())"/> 33 | </div> 34 | } 35 | </div> 36 | } 37 | </div> -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/GroupSelector.razor.cs: -------------------------------------------------------------------------------- 1 | using AwesomeBlazor.Models; 2 | using Microsoft.AspNetCore.Components; 3 | 4 | namespace AwesomeBlazorBrowser.Components; 5 | 6 | public partial class GroupSelector 7 | { 8 | [Inject] public HelperScriptService HelperScript { get; init; } = null!; 9 | 10 | [Parameter] 11 | public string ParentGroupAnchor { get; set; } = ""; 12 | 13 | [Parameter] 14 | public IEnumerable<AwesomeResourceGroup> Groups { get; set; } = Enumerable.Empty<AwesomeResourceGroup>(); 15 | 16 | [Parameter] 17 | public EventCallback<AwesomeResourceGroup> OnChangeGroupState { get; set; } 18 | 19 | [Parameter] 20 | public EventCallback OnClickGroupLink { get; set; } 21 | 22 | private async Task _OnClickGroupLink(string anchorName) 23 | { 24 | await this.HelperScript.ScrollToAnchorAsync(anchorName, smooth: true, changeUrl: true); 25 | await this.OnClickGroupLink.InvokeAsync(); 26 | } 27 | 28 | private Task OnClickToggleBox(AwesomeResourceGroup group) 29 | { 30 | group.SelectionState = group.SelectionState != SelectionState.Selected ? SelectionState.Selected : SelectionState.Unselected; 31 | return this.OnChangeGroupState.InvokeAsync(group); 32 | } 33 | 34 | private Task OnClickExpandBox(AwesomeResourceGroup group) 35 | { 36 | group.Expanded = !group.Expanded; 37 | return this.OnChangeGroupState.InvokeAsync(group); 38 | } 39 | 40 | public string GetSubGroupsHeight(AwesomeResourceGroup group) 41 | { 42 | var expandedDescendantsCount = group.GetExpandedDescendantsCount(); 43 | return (expandedDescendantsCount * 26) + "px"; 44 | } 45 | 46 | private Task _OnChangeSubGroupState(AwesomeResourceGroup group) 47 | { 48 | return this.OnChangeGroupState.InvokeAsync(group); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/GroupSelector.razor.scss: -------------------------------------------------------------------------------- 1 | @import '../icons.variables.scss'; 2 | 3 | $group-title-size: 26px; 4 | 5 | .group-selector { 6 | & > .group { 7 | a.link { 8 | transition: color linear 0.2s; 9 | } 10 | 11 | &:not(.visible) { 12 | a.link { 13 | color: var(--deadlink-text-color); 14 | cursor: default; 15 | pointer-events: none; 16 | 17 | &:hover { 18 | text-decoration: none; 19 | } 20 | } 21 | 22 | .toggle-box { 23 | color: var(--deadlink-text-color); 24 | } 25 | } 26 | 27 | & > .group-title { 28 | white-space: nowrap; 29 | height: $group-title-size; 30 | display: flex; 31 | 32 | & > .expand-box { 33 | display: inline-block; 34 | color: var(--default-text-color); 35 | text-decoration: none; 36 | transition: transform linear 0.2s; 37 | width: $group-title-size; 38 | height: $group-title-size; 39 | 40 | &:before { 41 | display: inline-block; 42 | content: $icon-expand-more; 43 | font-size: 18px; 44 | width: $group-title-size; 45 | height: $group-title-size; 46 | line-height: $group-title-size; 47 | text-align: center; 48 | } 49 | } 50 | } 51 | 52 | &.expanded { 53 | & > .group-title { 54 | & > .expand-box { 55 | transform: rotate(-180deg); 56 | } 57 | } 58 | } 59 | } 60 | 61 | .sub-group { 62 | padding-left: 10px; 63 | overflow: hidden; 64 | transition: height ease 0.2s; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/GroupsPanel.razor: -------------------------------------------------------------------------------- 1 | <div class="groups-panel"> 2 | 3 | <div class="header"> 4 | <label class="@CssClass("toggle-box", Group.SelectionState)"> 5 | <input type="button" @onclick="@(() => OnClickToggleBox(Group))" /> 6 | </label> 7 | <span class="text">Categories</span> 8 | </div> 9 | 10 | <div class="selector"> 11 | <GroupSelector Groups="Group.SubGroups" 12 | OnChangeGroupState="_OnChangeGroupState" 13 | OnClickGroupLink="@(() => OnClickGroupLink.InvokeAsync())" /> 14 | </div> 15 | </div> -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/GroupsPanel.razor.cs: -------------------------------------------------------------------------------- 1 | using AwesomeBlazor.Models; 2 | using Microsoft.AspNetCore.Components; 3 | 4 | namespace AwesomeBlazorBrowser.Components; 5 | 6 | public partial class GroupsPanel 7 | { 8 | [Parameter] 9 | public AwesomeResourceGroup Group { get; set; } = new AwesomeResourceGroup(); 10 | 11 | [Parameter] 12 | public EventCallback OnChangeGroupState { get; set; } 13 | 14 | [Parameter] 15 | public EventCallback OnClickGroupLink { get; set; } 16 | 17 | private Task _OnChangeGroupState(AwesomeResourceGroup group) 18 | { 19 | return this.OnChangeGroupState.InvokeAsync(group); 20 | } 21 | 22 | private Task OnClickToggleBox(AwesomeResourceGroup group) 23 | { 24 | group.SelectionState = group.SelectionState switch 25 | { 26 | SelectionState.Selected => SelectionState.Unselected, 27 | SelectionState.Unselected => SelectionState.Selected, 28 | _ => SelectionState.Selected 29 | }; 30 | 31 | return this.OnChangeGroupState.InvokeAsync(group); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/GroupsPanel.razor.scss: -------------------------------------------------------------------------------- 1 | @import "../site.mixin.scss"; 2 | $groups-panel-header-height: 48px; 3 | 4 | .groups-panel { 5 | position: absolute; 6 | top: 0; 7 | left: 0; 8 | bottom: 0; 9 | right: 0; 10 | 11 | & > .header { 12 | border-bottom: solid 1px var(--default-border-color); 13 | padding-left: 20px; 14 | height: $groups-panel-header-height; 15 | line-height: $groups-panel-header-height; 16 | display: flex; 17 | align-items: center; 18 | 19 | & > .text { 20 | display: inline-block; 21 | font-weight: 600; 22 | } 23 | } 24 | 25 | & > .selector { 26 | position: absolute; 27 | top: $groups-panel-header-height + 1px; 28 | left: 0; 29 | bottom: 0; 30 | right: 0; 31 | overflow-x: hidden; 32 | overflow-y: auto; 33 | padding: 10px 10px 10px 20px; 34 | 35 | @include scrollbar-color(var(--scrollbar-thumb-color), var(--scrollbar-back-color)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/Settings.razor: -------------------------------------------------------------------------------- 1 | <div class="settings"> 2 | <div class="theme"> 3 | <h3>Theme</h3> 4 | <div> 5 | <label> 6 | <input type="radio" name="theme" checked="@(_Theme == Theme.SystemDefault)" @onclick="@(() => OnClickTheme(Theme.SystemDefault))" /> 7 | <span class="icon icon-light-mode"></span> 8 | <span>System Default</span> 9 | </label> 10 | </div> 11 | <div> 12 | <label> 13 | <input type="radio" name="theme" checked="@(_Theme == Theme.LightMode)" @onclick="@(() => OnClickTheme(Theme.LightMode))" /> 14 | <span class="icon icon-light-mode"></span> 15 | <span>Light</span> 16 | </label> 17 | </div> 18 | <div> 19 | <label> 20 | <input type="radio" name="theme" checked="@(_Theme == Theme.DarkMode)" @onclick="@(() => OnClickTheme(Theme.DarkMode))" /> 21 | <span class="icon icon-dark-mode"></span> 22 | <span>Dark</span> 23 | </label> 24 | </div> 25 | </div> 26 | </div> 27 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/Settings.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | 3 | namespace AwesomeBlazorBrowser.Components; 4 | 5 | public partial class Settings 6 | { 7 | private Theme _Theme; 8 | 9 | [Inject] public HelperScriptService HelperScript { get; init; } = null!; 10 | 11 | protected override async Task OnAfterRenderAsync(bool firstRender) 12 | { 13 | if (firstRender) 14 | { 15 | this._Theme = await this.HelperScript.GetCurrentThemeAsync(); 16 | this.StateHasChanged(); 17 | } 18 | } 19 | 20 | private async Task OnClickTheme(Theme theme) 21 | { 22 | this._Theme = theme; 23 | await this.HelperScript.SetCurrentThemeAsync(this._Theme); 24 | } 25 | } -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Components/Settings.razor.scss: -------------------------------------------------------------------------------- 1 | .settings { 2 | padding: 4px 0 0 10px; 3 | font-size: 14px; 4 | 5 | & h3:first-child { 6 | margin-top: 0; 7 | } 8 | 9 | h3 { 10 | margin-bottom: 0; 11 | } 12 | 13 | & > .theme { 14 | .icon { 15 | margin-right: 4px; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/HelperScriptService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.JSInterop; 2 | 3 | namespace AwesomeBlazorBrowser; 4 | 5 | public class HelperScriptService : IAsyncDisposable 6 | { 7 | private readonly IJSRuntime _JsRuntime; 8 | 9 | private IJSObjectReference? _Helper; 10 | 11 | public HelperScriptService(IJSRuntime jsRuntime) 12 | { 13 | this._JsRuntime = jsRuntime; 14 | } 15 | 16 | private async ValueTask<IJSObjectReference> GetHelperAsync() 17 | { 18 | this._Helper ??= await this._JsRuntime.InvokeAsync<IJSObjectReference>("import", "./scripts/helper.js"); 19 | return this._Helper; 20 | } 21 | 22 | public async ValueTask InstallHashWatcherAsync() 23 | { 24 | var helper = await this.GetHelperAsync(); 25 | await helper.InvokeVoidAsync("installHashWatcher"); 26 | } 27 | 28 | public async ValueTask ScrollToAnchorAsync(string anchorName, bool smooth, bool changeUrl = false) 29 | { 30 | var helper = await this.GetHelperAsync(); 31 | await helper.InvokeVoidAsync("scrollToAnchor", anchorName.TrimStart('#'), smooth, changeUrl); 32 | } 33 | 34 | public async ValueTask<Theme> GetCurrentThemeAsync() 35 | { 36 | var helper = await this.GetHelperAsync(); 37 | var themeStr = await helper.InvokeAsync<string>("getCurrentTheme"); 38 | return ThemeExtension.Parse(themeStr); 39 | } 40 | 41 | public async ValueTask SetCurrentThemeAsync(Theme theme) 42 | { 43 | var helper = await this.GetHelperAsync(); 44 | await helper.InvokeVoidAsync("setCurrentTheme", theme.ToKebabCase()); 45 | } 46 | 47 | public async ValueTask DisposeAsync() 48 | { 49 | if (this._Helper is not null) 50 | { 51 | try { await this._Helper.DisposeAsync(); } 52 | catch (JSDisconnectedException) { } 53 | finally { this._Helper = null; } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Program.cs: -------------------------------------------------------------------------------- 1 | using AwesomeBlazorBrowser; 2 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 3 | 4 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 5 | builder.RootComponents.Add<App>("#app"); 6 | ConfigureServices(builder.Services, builder.HostEnvironment); 7 | await builder.Build().RunAsync(); 8 | 9 | void ConfigureServices(IServiceCollection services, IWebAssemblyHostEnvironment hostEnvironment) 10 | { 11 | services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(hostEnvironment.BaseAddress) }); 12 | services.AddScoped<HelperScriptService>(); 13 | } -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Properties/PublishProfiles/for GitHub Pages.pubxml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <!-- 3 | https://go.microsoft.com/fwlink/?LinkID=208121. 4 | --> 5 | <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 6 | <PropertyGroup> 7 | <DeleteExistingFiles>False</DeleteExistingFiles> 8 | <ExcludeApp_Data>False</ExcludeApp_Data> 9 | <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish> 10 | <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration> 11 | <LastUsedPlatform>Any CPU</LastUsedPlatform> 12 | <PublishProvider>FileSystem</PublishProvider> 13 | <PublishUrl>bin\Release\net6.0\publish\</PublishUrl> 14 | <WebPublishMethod>FileSystem</WebPublishMethod> 15 | <SiteUrlToLaunchAfterPublish /> 16 | <TargetFramework>net6.0</TargetFramework> 17 | <ProjectGuid>4a9a86ed-a7b1-484c-946b-43f1fce69aa2</ProjectGuid> 18 | <SelfContained>false</SelfContained> 19 | </PropertyGroup> 20 | </Project> -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:57524/", 7 | "sslPort": 44382 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "AwesomeBlazorBrowser": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "hotReloadProfile": "blazorwasm", 23 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 24 | "applicationUrl": "http://localhost:57528/;https://localhost:57529/", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | }, 29 | "AwesomeBlazorBrowser (tunneling)": { 30 | "commandName": "Project", 31 | "launchBrowser": true, 32 | "hotReloadProfile": "blazorwasm", 33 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 34 | "applicationUrl": "http://localhost:57528/;https://localhost:57529/", 35 | "createTunnel": true, 36 | "tunnelAuthentication": "public", 37 | "environmentVariables": { 38 | "ASPNETCORE_ENVIRONMENT": "Development" 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/Theme.cs: -------------------------------------------------------------------------------- 1 | namespace AwesomeBlazorBrowser; 2 | 3 | public enum Theme 4 | { 5 | SystemDefault, 6 | LightMode, 7 | DarkMode 8 | } 9 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/ThemeExtension.cs: -------------------------------------------------------------------------------- 1 | namespace AwesomeBlazorBrowser; 2 | 3 | public static class ThemeExtension 4 | { 5 | public static Theme Parse(string themeString) 6 | { 7 | return themeString.ToLower() switch 8 | { 9 | "theme-system-default" => Theme.SystemDefault, 10 | "theme-light-mode" => Theme.LightMode, 11 | "theme-dark-mode" => Theme.DarkMode, 12 | _ => Theme.SystemDefault 13 | }; 14 | } 15 | 16 | public static string ToKebabCase(this Theme theme) 17 | { 18 | return theme switch 19 | { 20 | Theme.SystemDefault => "theme-system-default", 21 | Theme.LightMode => "theme-light-mode", 22 | Theme.DarkMode => "theme-dark-mode", 23 | _ => "theme-system-default" 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 7 | @using Microsoft.JSInterop 8 | @using AwesomeBlazorBrowser 9 | @using AwesomeBlazorBrowser.Components 10 | @* @using Toolbelt.Blazor.Components *@ 11 | 12 | @using static Toolbelt.Web.CssClassInlineBuilder.V2 13 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/compilerconfig.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputFile": "site.scss", 4 | "outputFile": "wwwroot/css/site.css" 5 | } 6 | ] -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/compilerconfig.json.defaults: -------------------------------------------------------------------------------- 1 | { 2 | "compilers": { 3 | "less": { 4 | "autoPrefix": "", 5 | "cssComb": "none", 6 | "ieCompat": true, 7 | "strictMath": false, 8 | "strictUnits": false, 9 | "relativeUrls": true, 10 | "rootPath": "", 11 | "sourceMapRoot": "", 12 | "sourceMapBasePath": "", 13 | "sourceMap": false 14 | }, 15 | "sass": { 16 | "autoPrefix": "", 17 | "includePath": "", 18 | "indentType": "space", 19 | "indentWidth": 2, 20 | "outputStyle": "nested", 21 | "Precision": 5, 22 | "relativeUrls": true, 23 | "sourceMapRoot": "", 24 | "lineFeed": "", 25 | "sourceMap": false 26 | }, 27 | "stylus": { 28 | "sourceMap": false 29 | }, 30 | "babel": { 31 | "sourceMap": false 32 | }, 33 | "coffeescript": { 34 | "bare": false, 35 | "runtimeMode": "node", 36 | "sourceMap": false 37 | }, 38 | "handlebars": { 39 | "root": "", 40 | "noBOM": false, 41 | "name": "", 42 | "namespace": "", 43 | "knownHelpersOnly": false, 44 | "forcePartial": false, 45 | "knownHelpers": [], 46 | "commonjs": "", 47 | "amd": false, 48 | "sourceMap": false 49 | } 50 | }, 51 | "minifiers": { 52 | "css": { 53 | "enabled": true, 54 | "termSemicolons": true, 55 | "gzip": false 56 | }, 57 | "javascript": { 58 | "enabled": true, 59 | "termSemicolons": true, 60 | "gzip": false 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/helper.ts: -------------------------------------------------------------------------------- 1 | export const scrollToAnchor = (anchorName: string, smooth?: boolean, changeUrl?: boolean): void => { 2 | try { 3 | const element = document.querySelector(`a[name=${anchorName}]`); 4 | if (element !== null) { 5 | element.scrollIntoView({ behavior: smooth === true ? 'smooth' : 'auto' }); 6 | if (changeUrl === true) { 7 | const href = location.href.split('#')[0]; 8 | history.pushState(null, document.title, `${href}#${anchorName}`); 9 | } 10 | } 11 | } 12 | catch (error) { 13 | console.error(error); 14 | } 15 | } 16 | 17 | export const getCurrentTheme = (): string => { 18 | return localStorage.getItem("theme") || "theme-system-default"; 19 | } 20 | 21 | export const setCurrentTheme = (theme: string): void => { 22 | localStorage.setItem("theme", theme); 23 | document.body.classList.remove("theme-system-default", "theme-light-mode", "theme-dark-mode"); 24 | document.body.classList.add(theme); 25 | 26 | } 27 | 28 | export const installHashWatcher = (): void => { 29 | 30 | const locationHashChanged = (): void => { 31 | const hash = location.hash.split('#').pop() || ''; 32 | if (hash !== '') { 33 | scrollToAnchor(hash, false, false); 34 | } 35 | } 36 | 37 | window.addEventListener("hashchange", locationHashChanged); 38 | } 39 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/icons.scss: -------------------------------------------------------------------------------- 1 | @import "icons.variables.scss"; 2 | 3 | @font-face { 4 | font-family: '#{$icomoon-font-family}'; 5 | src: url('#{$icomoon-font-path}/#{$icomoon-font-family}.ttf?dia7uy') format('truetype'), url('#{$icomoon-font-path}/#{$icomoon-font-family}.woff?dia7uy') format('woff'), url('#{$icomoon-font-path}/#{$icomoon-font-family}.svg?dia7uy##{$icomoon-font-family}') format('svg'); 6 | font-weight: normal; 7 | font-style: normal; 8 | font-display: block; 9 | } 10 | 11 | .icon { 12 | /* use !important to prevent issues with browser extensions that change fonts */ 13 | font-family: '#{$icomoon-font-family}' !important; 14 | speak: none; 15 | font-style: normal; 16 | font-weight: normal; 17 | font-variant: normal; 18 | text-transform: none; 19 | line-height: 1; 20 | /* Better Font Rendering =========== */ 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | } 24 | 25 | .icon-checkbox-blank { 26 | &:before { 27 | content: $icon-checkbox-blank; 28 | } 29 | } 30 | 31 | .icon-checkbox-checked { 32 | &:before { 33 | content: $icon-checkbox-checked; 34 | } 35 | } 36 | 37 | .icon-checkbox-indeterminate { 38 | &:before { 39 | content: $icon-checkbox-indeterminate; 40 | } 41 | } 42 | 43 | .icon-expand-less { 44 | &:before { 45 | content: $icon-expand-less; 46 | } 47 | } 48 | 49 | .icon-expand-more { 50 | &:before { 51 | content: $icon-expand-more; 52 | } 53 | } 54 | 55 | .icon-link { 56 | &:before { 57 | content: $icon-link; 58 | } 59 | } 60 | 61 | .icon-logo-blazor-large { 62 | &:before { 63 | content: $icon-logo-blazor-large; 64 | } 65 | } 66 | 67 | .icon-mark-github { 68 | &:before { 69 | content: $icon-mark-github; 70 | } 71 | } 72 | 73 | .icon-menu { 74 | &:before { 75 | content: $icon-menu; 76 | } 77 | } 78 | 79 | .icon-settings { 80 | &:before { 81 | content: $icon-settings; 82 | } 83 | } 84 | 85 | .icon-light-mode { 86 | &:before { 87 | content: $icon-light-mode; 88 | } 89 | } 90 | 91 | .icon-dark-mode { 92 | &:before { 93 | content: $icon-dark-mode; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/icons.variables.scss: -------------------------------------------------------------------------------- 1 | $icomoon-font-family: "Awesome-Blazor-Browser-Icons" !default; 2 | $icomoon-font-path: "wwwroot/css/fonts" !default; 3 | 4 | $icon-checkbox-blank: "\e901"; 5 | $icon-checkbox-checked: "\e902"; 6 | $icon-checkbox-indeterminate: "\e904"; 7 | $icon-expand-less: "\e900"; 8 | $icon-expand-more: "\e903"; 9 | $icon-link: "\e905"; 10 | $icon-logo-blazor-large: "\e906"; 11 | $icon-mark-github: "\e907"; 12 | $icon-menu: "\e908"; 13 | $icon-settings: "\e909"; 14 | $icon-light-mode: "\e90a"; 15 | $icon-dark-mode: "\e90b"; 16 | 17 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/site.mixin.scss: -------------------------------------------------------------------------------- 1 | @mixin scrollbar-color($thumb-color, $back-color) { 2 | &::-webkit-scrollbar { 3 | width: 12px; 4 | } 5 | 6 | & { 7 | scrollbar-width: thin; 8 | scrollbar-color: $thumb-color $back-color; 9 | } 10 | 11 | &::-webkit-scrollbar-track { 12 | background: $back-color; 13 | } 14 | 15 | &::-webkit-scrollbar-thumb { 16 | background-color: $thumb-color; 17 | border-radius: 6px; 18 | border: solid 2px $back-color; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/site.scss: -------------------------------------------------------------------------------- 1 | @import "site.theme.scss"; 2 | 3 | body, input[type=text] { 4 | font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji; 5 | color: var(--default-text-color); 6 | } 7 | 8 | body { 9 | font-size: 16px; 10 | line-height: 1.5; 11 | background-color: var(--default-back-color); 12 | } 13 | 14 | input[type=text] { 15 | font-size: 14px; 16 | } 17 | 18 | a { 19 | color: var(--default-link-color); 20 | text-decoration: none; 21 | 22 | &:hover { 23 | text-decoration: underline; 24 | } 25 | 26 | &.clickable { 27 | cursor: default; 28 | user-select: none; 29 | transition: color linear 0.2s; 30 | 31 | &:hover { 32 | color: var(--default-link-color-light); 33 | text-decoration: none; 34 | } 35 | } 36 | } 37 | 38 | @import 'icons.scss'; 39 | @import 'toggle-box.scss'; 40 | @import 'App.razor.scss'; 41 | @import 'Components/AppBar.razor.scss'; 42 | @import 'Components/GroupsPanel.razor.scss'; 43 | @import 'Components/GroupSelector.razor.scss'; 44 | @import 'Components/Contents.razor.scss'; 45 | @import 'Components/Footer.razor.scss'; 46 | @import 'Components/Settings.razor.scss'; 47 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/site.theme.scss: -------------------------------------------------------------------------------- 1 | // light theme 2 | @mixin theme-light-mode { 3 | --default-back-color: #ffffff; 4 | --default-text-color: #24292f; 5 | --default-link-color: #0366d6; 6 | --default-link-color-light: #75b5fd; 7 | --default-border-color: #d0d7de; 8 | --quote-text-color: #6a737d; 9 | --quote-text-line-color: #dfe2e5; 10 | --header-text-line-color: #d8dee4; 11 | --weaked-text-color: #c0c0c0; 12 | --deadlink-text-color: #c0c0c0; 13 | --appbar-back-color: #24292e; 14 | --appbar-text-color: #ffffff; 15 | --searchbox-back-color: var(--appbar-back-color); 16 | --searchbox-back-color-focused: #ffffff; 17 | --searchbox-border-color: #57606a; 18 | --searchbox-text-color: #ffffff; 19 | --searchbox-text-color-focused: #000000; 20 | --footer-back-color: #e0e0e0; 21 | --footer-text-color: #606060; 22 | --scrollbar-back-color: #f1f1f1; 23 | --scrollbar-thumb-color: #a8a8a8; 24 | } 25 | 26 | // dark theme 27 | @mixin theme-dark-mode { 28 | --default-back-color: #22272e; 29 | --default-text-color: #aebac6; 30 | --default-link-color: #449bf1; 31 | --default-link-color-light: #70b2ef; 32 | --default-border-color: #454c55; 33 | --header-text-line-color: #454c55; 34 | --weaked-text-color: #77838f; 35 | --deadlink-text-color: #586168; 36 | --quote-text-color: #768390; 37 | --quote-text-line-color: #444c56; 38 | --appbar-back-color: #2d333b; 39 | --appbar-text-color: var(---default-text-color); 40 | --searchbox-back-color: #22272e; 41 | --searchbox-back-color-focused: #2d333b; 42 | --searchbox-border-color: #454c55; 43 | --searchbox-text-color: #aebac6; 44 | --searchbox-text-color-focused: #aebac6; 45 | --footer-back-color: var(--appbar-back-color); 46 | --footer-text-color: var(--weaked-text-color); 47 | --scrollbar-back-color: #424242; 48 | --scrollbar-thumb-color: #7b7b7b; 49 | } 50 | 51 | body.theme-system-default, body.theme-light-mode { 52 | @include theme-light-mode(); 53 | } 54 | 55 | @media (prefers-color-scheme: dark) { 56 | body.theme-system-default, body.theme-dark-mode { 57 | @include theme-dark-mode(); 58 | } 59 | } 60 | 61 | body.theme-dark-mode { 62 | @include theme-dark-mode(); 63 | } 64 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/site.variables.scss: -------------------------------------------------------------------------------- 1 | $breakpoints-sm: 600px; 2 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/theme-initializer.ts: -------------------------------------------------------------------------------- 1 | const theme = localStorage.getItem("theme") || "theme-system-default"; 2 | document.body.classList.add(theme); 3 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/toggle-box.scss: -------------------------------------------------------------------------------- 1 | @import "icons.variables.scss"; 2 | 3 | .toggle-box { 4 | input { 5 | display: none; 6 | } 7 | 8 | font-family: '#{$icomoon-font-family}'; 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | line-height: 1; 12 | position: relative; 13 | transition: color linear 0.2s; 14 | color: var(--default-link-color); 15 | font-size: 0; 16 | width: 24px; 17 | height: 24px; 18 | margin-right: 4px; 19 | vertical-align: middle; 20 | 21 | &:hover { 22 | color: var(--default-link-color-light); 23 | } 24 | 25 | &:after { 26 | content: ''; 27 | display: inline-block; 28 | width: 32px; 29 | height: 32px; 30 | position: absolute; 31 | border-radius: 16px; 32 | background-color: var(--default-link-color-light); 33 | z-index: -1; 34 | opacity: 0.5; 35 | transform: scale(0); 36 | top: -5px; 37 | left: -4px; 38 | transition: transform ease-out 0.1s; 39 | } 40 | 41 | &:active:after { 42 | transform: scale(1); 43 | } 44 | 45 | &:before { 46 | font-size: 24px; 47 | } 48 | 49 | &.unselected:before { 50 | content: $icon-checkbox-blank; 51 | } 52 | 53 | &.selected:before { 54 | content: $icon-checkbox-checked; 55 | } 56 | 57 | &.selected-any:before { 58 | content: $icon-checkbox-indeterminate; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "ES2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ 22 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | 26 | /* Modules */ 27 | "module": "ES2015", /* Specify what module code is generated. */ 28 | // "rootDir": "./", /* Specify the root folder within your source files. */ 29 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 30 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 31 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 32 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 33 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ 34 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 35 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 36 | // "resolveJsonModule": true, /* Enable importing .json files */ 37 | // "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */ 38 | 39 | /* JavaScript Support */ 40 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ 41 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 42 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ 43 | 44 | /* Emit */ 45 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 46 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 47 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 48 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 49 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ 50 | "outDir": "./wwwroot/scripts", /* Specify an output folder for all emitted files. */ 51 | // "removeComments": true, /* Disable emitting comments. */ 52 | // "noEmit": true, /* Disable emitting files from a compilation. */ 53 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 54 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ 55 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 56 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 59 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 60 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 61 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 62 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ 63 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ 64 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 65 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ 66 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 67 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 68 | 69 | /* Interop Constraints */ 70 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 71 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 72 | "esModuleInterop": false, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ 73 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 74 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 75 | 76 | /* Type Checking */ 77 | "strict": true, /* Enable all strict type-checking options. */ 78 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ 79 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ 80 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 81 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ 82 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 83 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ 84 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ 85 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 86 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ 87 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ 88 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 89 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 90 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 91 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 92 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 93 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ 94 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 95 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 96 | 97 | /* Completeness */ 98 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 99 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 100 | }, 101 | "compileOnSave": true 102 | 103 | } 104 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/wwwroot/css/fonts/Awesome-Blazor-Browser-Icons.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" standalone="no"?> 2 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > 3 | <svg xmlns="http://www.w3.org/2000/svg"> 4 | <metadata>Generated by IcoMoon</metadata> 5 | <defs> 6 | <font id="Awesome-Blazor-Browser-Icons" horiz-adv-x="1024"> 7 | <font-face units-per-em="1024" ascent="960" descent="-64" /> 8 | <missing-glyph horiz-adv-x="1024" /> 9 | <glyph unicode=" " horiz-adv-x="512" d="" /> 10 | <glyph unicode="" glyph-name="expand-less" d="M481.707 588.373l-195.84-195.84c-16.64-16.64-16.64-43.52 0-60.16s43.52-16.64 60.16 0l165.973 165.547 165.547-165.547c16.64-16.64 43.52-16.64 60.16 0s16.64 43.52 0 60.16l-195.84 195.84c-16.213 16.64-43.52 16.64-60.16 0z" /> 11 | <glyph unicode="" glyph-name="checkbox-blank" d="M768 149.333h-512c-23.467 0-42.667 19.2-42.667 42.667v512c0 23.467 19.2 42.667 42.667 42.667h512c23.467 0 42.667-19.2 42.667-42.667v-512c0-23.467-19.2-42.667-42.667-42.667zM810.667 832h-597.333c-46.933 0-85.333-38.4-85.333-85.333v-597.333c0-46.933 38.4-85.333 85.333-85.333h597.333c46.933 0 85.333 38.4 85.333 85.333v597.333c0 46.933-38.4 85.333-85.333 85.333z" /> 12 | <glyph unicode="" glyph-name="checkbox-checked" d="M810.667 832h-597.333c-46.933 0-85.333-38.4-85.333-85.333v-597.333c0-46.933 38.4-85.333 85.333-85.333h597.333c46.933 0 85.333 38.4 85.333 85.333v597.333c0 46.933-38.4 85.333-85.333 85.333zM456.96 264.96c-16.64-16.64-43.52-16.64-60.16 0l-153.173 153.173c-16.64 16.64-16.64 43.52 0 60.16s43.52 16.64 60.16 0l122.88-122.88 293.547 293.547c16.64 16.64 43.52 16.64 60.16 0s16.64-43.52 0-60.16l-323.413-323.84z" /> 13 | <glyph unicode="" glyph-name="expand-more" d="M677.547 563.627l-165.547-165.547-165.547 165.547c-16.64 16.64-43.52 16.64-60.16 0s-16.64-43.52 0-60.16l195.84-195.84c16.64-16.64 43.52-16.64 60.16 0l195.84 195.84c16.64 16.64 16.64 43.52 0 60.16-16.64 16.213-43.947 16.64-60.587 0z" /> 14 | <glyph unicode="" glyph-name="checkbox-indeterminate" d="M810.667 832h-597.333c-46.933 0-85.333-38.4-85.333-85.333v-597.333c0-46.933 38.4-85.333 85.333-85.333h597.333c46.933 0 85.333 38.4 85.333 85.333v597.333c0 46.933-38.4 85.333-85.333 85.333zM725.333 405.333h-426.667v85.333h426.667v-85.333z" /> 15 | <glyph unicode="" glyph-name="link" d="M256 384h64v-64h-64c-96 0-192 108.16-192 224s99.2 224 192 224h256c92.8 0 192-108.16 192-224 0-90.24-58.24-174.080-128-208v74.24c37.12 28.8 64 81.28 64 133.76 0 81.92-65.28 160-128 160h-256c-62.72 0-128-78.080-128-160s64-160 128-160zM832 576h-64v-64h64c64 0 128-78.080 128-160s-65.28-160-128-160h-256c-62.72 0-128 78.080-128 160 0 53.12 26.88 104.96 64 133.76v74.24c-69.76-33.92-128-117.76-128-208 0-115.84 99.2-224 192-224h256c92.8 0 192 108.16 192 224s-96 224-192 224z" /> 16 | <glyph unicode="" glyph-name="logo-blazor-large" d="M965.632 910.541c-1.331-0.717-5.222-6.451-9.421-13.824-33.178-59.392-65.638-99.84-103.731-129.536-35.021-27.238-79.155-48.947-129.843-63.693-20.48-5.939-22.63-4.096-13.21 11.469 22.938 37.99 38.81 82.227 45.363 126.771 2.56 17.92 2.56 19.763-0.614 21.197-3.072 1.331-6.042-0.307-10.752-6.246-4.096-5.018-24.166-23.245-35.84-32.461-38.502-30.413-87.245-53.658-135.168-64.307-31.744-6.963-31.744-6.963-130.048-7.782-56.627-0.512-93.389-1.229-99.84-1.946-50.381-5.837-92.467-18.534-136.192-40.96-35.738-18.33-62.157-37.478-91.238-66.15-85.094-84.173-125.952-200.704-112.538-321.024 8.294-74.445 36.352-143.258 81.101-199.168 11.469-14.438 34.509-37.99 48.947-50.176 54.989-46.49 124.109-75.878 199.066-84.992 40.755-4.915 99.533-3.482 149.606 3.686 102.4 14.541 193.126 54.886 268.39 119.398 16.998 14.643 44.954 42.189 44.954 44.442 0 1.126-0.307 1.946-0.614 1.946-0.41 0-6.042-3.379-12.595-7.475-103.629-65.331-230.298-101.069-358.195-101.069-23.347 0-54.784 1.946-73.421 4.608-149.606 20.992-262.451 133.427-279.654 278.528-3.072 26.214-1.741 65.946 3.174 92.672 10.65 58.163 38.4 113.664 78.848 157.901 42.598 46.49 101.683 80.794 162.714 94.515 26.829 6.042 37.376 7.066 70.144 7.066s43.315-1.024 70.144-7.066c72.090-16.179 138.342-59.494 183.603-119.91 35.328-47.206 56.934-105.472 62.771-169.677 1.638-18.227 0.717-48.538-1.946-60.928-12.288-56.422-49.766-95.539-98.509-102.707-10.342-1.434-29.901-0.717-40.96 1.638-27.238 5.632-49.766 19.456-64.614 39.424l-5.018 6.861-11.059-10.854c-11.981-11.981-24.678-20.992-40.141-28.774-43.315-21.709-94.618-21.197-138.035 1.536-14.95 7.782-25.6 15.77-38.605 28.672-21.914 21.709-36.147 48.026-43.008 79.36-2.253 10.342-3.174 37.888-1.638 49.664 4.608 34.816 19.763 65.331 45.158 90.624 22.426 22.528 48.128 36.454 79.77 43.213 9.114 2.048 14.029 2.15 66.56 2.56 49.664 0.41 57.651 0.205 65.024-1.229 24.371-4.915 43.315-22.63 50.483-47.104 1.536-5.427 1.843-13.824 2.355-74.24 0.717-75.571 0.512-72.704 7.885-87.859 6.963-14.234 19.763-23.962 35.942-27.341 26.112-5.632 47.411 4.71 59.187 28.672 7.066 14.438 8.806 22.323 9.318 44.544 1.024 39.834-7.168 76.083-25.805 114.278-13.21 26.829-28.672 48.026-51.405 70.042-32.358 31.539-70.246 52.941-113.357 64-19.866 5.12-32.563 6.758-55.91 7.373-32.563 0.819-56.934-2.662-87.040-12.595-16.691-5.53-44.749-19.149-58.88-28.57-49.869-33.28-86.118-82.022-103.219-138.752-9.626-31.949-13.107-68.198-9.523-99.328 6.451-55.501 33.382-107.827 76.595-148.992 21.299-20.275 42.906-35.123 70.963-48.742 45.568-22.221 87.040-29.696 156.16-28.16 61.542 1.331 107.213 8.090 160.256 23.654 166.912 49.254 308.326 172.544 377.754 329.421 30.925 69.939 45.466 135.987 47.411 215.347 1.946 82.842-13.107 154.931-45.568 216.986-6.144 11.776-8.192 13.722-12.493 11.571zM355.123 463.77c-34.304-6.144-62.771-32.256-72.704-66.458-2.048-7.168-2.355-10.342-2.355-25.6 0.102-16.282 0.307-17.92 2.97-26.112 5.734-17.306 12.902-28.672 25.907-41.062 31.949-30.515 80.896-33.587 117.658-7.578 8.192 5.837 20.48 19.046 25.293 27.238 5.018 8.499 9.318 19.866 11.366 29.798 1.331 6.554 1.638 16.282 1.638 58.061v50.176l-2.253 1.536c-2.048 1.434-8.499 1.638-50.995 1.536-36.659-0.102-50.586-0.41-56.525-1.536z" /> 17 | <glyph unicode="" glyph-name="mark-github" d="M512 960c-282.88 0-512-229.12-512-512 0-226.56 146.56-417.92 350.080-485.76 25.6-4.48 35.2 10.88 35.2 24.32 0 12.16-0.64 52.48-0.64 95.36-128.64-23.68-161.92 31.36-172.16 60.16-5.76 14.72-30.72 60.16-52.48 72.32-17.92 9.6-43.52 33.28-0.64 33.92 40.32 0.64 69.12-37.12 78.72-52.48 46.080-77.44 119.68-55.68 149.12-42.24 4.48 33.28 17.92 55.68 32.64 68.48-113.92 12.8-232.96 56.96-232.96 252.8 0 55.68 19.84 101.76 52.48 137.6-5.12 12.8-23.040 65.28 5.12 135.68 0 0 42.88 13.44 140.8-52.48 40.96 11.52 84.48 17.28 128 17.28s87.040-5.76 128-17.28c97.92 66.56 140.8 52.48 140.8 52.48 28.16-70.4 10.24-122.88 5.12-135.68 32.64-35.84 52.48-81.28 52.48-137.6 0-196.48-119.68-240-233.6-252.8 18.56-16 34.56-46.72 34.56-94.72 0-68.48-0.64-123.52-0.64-140.8 0-13.44 9.6-29.44 35.2-24.32 204.471 70.528 348.741 261.288 348.8 485.753v0.007c0 282.88-229.12 512-512 512z" /> 18 | <glyph unicode="" glyph-name="list_black_24dp" d="M128 405.333h85.333v85.333h-85.333v-85.333zM128 234.667h85.333v85.333h-85.333v-85.333zM128 576h85.333v85.333h-85.333v-85.333zM298.667 405.333h597.333v85.333h-597.333v-85.333zM298.667 234.667h597.333v85.333h-597.333v-85.333zM298.667 661.333v-85.333h597.333v85.333h-597.333z" /> 19 | <glyph unicode="" glyph-name="settings_black_24dp" d="M829.013 406.187c1.707 13.653 2.987 27.307 2.987 41.813s-1.28 28.16-2.987 41.813l90.027 70.4c8.107 6.4 10.24 17.92 5.12 27.307l-85.333 147.627c-3.84 6.827-11.093 10.667-18.773 10.667-2.56 0-5.12-0.427-7.253-1.28l-106.24-42.667c-22.187 17.067-46.080 31.147-72.107 41.813l-16.213 113.067c-1.28 10.24-10.24 17.92-20.907 17.92h-170.667c-10.667 0-19.627-7.68-20.907-17.92l-16.213-113.067c-26.027-10.667-49.92-25.173-72.107-41.813l-106.24 42.667c-2.56 0.853-5.12 1.28-7.68 1.28-7.253 0-14.507-3.84-18.347-10.667l-85.333-147.627c-5.547-9.387-2.987-20.907 5.12-27.307l90.027-70.4c-1.707-13.653-2.987-27.733-2.987-41.813s1.28-28.16 2.987-41.813l-90.027-70.4c-8.107-6.4-10.24-17.92-5.12-27.307l85.333-147.627c3.84-6.827 11.093-10.667 18.773-10.667 2.56 0 5.12 0.427 7.253 1.28l106.24 42.667c22.187-17.067 46.080-31.147 72.107-41.813l16.213-113.067c1.28-10.24 10.24-17.92 20.907-17.92h170.667c10.667 0 19.627 7.68 20.907 17.92l16.213 113.067c26.027 10.667 49.92 25.173 72.107 41.813l106.24-42.667c2.56-0.853 5.12-1.28 7.68-1.28 7.253 0 14.507 3.84 18.347 10.667l85.333 147.627c5.12 9.387 2.987 20.907-5.12 27.307l-90.027 70.4zM744.533 479.147c1.707-13.227 2.133-22.187 2.133-31.147s-0.853-18.347-2.133-31.147l-5.973-48.213 37.973-29.867 46.080-35.84-29.867-51.627-54.187 21.76-44.373 17.92-38.4-29.013c-18.347-13.653-35.84-23.893-53.333-31.147l-45.227-18.347-6.827-48.213-8.533-57.6h-59.733l-8.107 57.6-6.827 48.213-45.227 18.347c-18.347 7.68-35.413 17.493-52.48 30.293l-38.827 29.867-45.227-18.347-54.187-21.76-29.867 51.627 46.080 35.84 37.973 29.867-5.973 48.213c-1.28 13.227-2.133 23.040-2.133 31.573s0.853 18.347 2.133 31.147l5.973 48.213-37.973 29.867-46.080 35.84 29.867 51.627 54.187-21.76 44.373-17.92 38.4 29.013c18.347 13.653 35.84 23.893 53.333 31.147l45.227 18.347 6.827 48.213 8.533 57.6h59.307l8.107-57.6 6.827-48.213 45.227-18.347c18.347-7.68 35.413-17.493 52.48-30.293l38.827-29.867 45.227 18.347 54.187 21.76 29.867-51.627-45.653-36.267-37.973-29.867 5.973-48.213zM512 618.667c-94.293 0-170.667-76.373-170.667-170.667s76.373-170.667 170.667-170.667 170.667 76.373 170.667 170.667-76.373 170.667-170.667 170.667zM512 362.667c-46.933 0-85.333 38.4-85.333 85.333s38.4 85.333 85.333 85.333 85.333-38.4 85.333-85.333-38.4-85.333-85.333-85.333z" /> 20 | <glyph unicode="" glyph-name="light_mode_black_24dp" d="M512 661.333c-117.76 0-213.333-95.573-213.333-213.333s95.573-213.333 213.333-213.333 213.333 95.573 213.333 213.333-95.573 213.333-213.333 213.333v0zM85.333 405.333h85.333c23.467 0 42.667 19.2 42.667 42.667s-19.2 42.667-42.667 42.667h-85.333c-23.467 0-42.667-19.2-42.667-42.667s19.2-42.667 42.667-42.667zM853.333 405.333h85.333c23.467 0 42.667 19.2 42.667 42.667s-19.2 42.667-42.667 42.667h-85.333c-23.467 0-42.667-19.2-42.667-42.667s19.2-42.667 42.667-42.667zM469.333 874.667v-85.333c0-23.467 19.2-42.667 42.667-42.667s42.667 19.2 42.667 42.667v85.333c0 23.467-19.2 42.667-42.667 42.667s-42.667-19.2-42.667-42.667zM469.333 106.667v-85.333c0-23.467 19.2-42.667 42.667-42.667s42.667 19.2 42.667 42.667v85.333c0 23.467-19.2 42.667-42.667 42.667s-42.667-19.2-42.667-42.667zM255.573 764.587c-16.64 16.64-43.947 16.64-60.16 0-16.64-16.64-16.64-43.947 0-60.16l45.227-45.227c16.64-16.64 43.947-16.64 60.16 0s16.64 43.947 0 60.16l-45.227 45.227zM783.36 236.8c-16.64 16.64-43.947 16.64-60.16 0-16.64-16.64-16.64-43.947 0-60.16l45.227-45.227c16.64-16.64 43.947-16.64 60.16 0 16.64 16.64 16.64 43.947 0 60.16l-45.227 45.227zM828.587 704.427c16.64 16.64 16.64 43.947 0 60.16-16.64 16.64-43.947 16.64-60.16 0l-45.227-45.227c-16.64-16.64-16.64-43.947 0-60.16s43.947-16.64 60.16 0l45.227 45.227zM300.8 176.64c16.64 16.64 16.64 43.947 0 60.16-16.64 16.64-43.947 16.64-60.16 0l-45.227-45.227c-16.64-16.64-16.64-43.947 0-60.16s43.947-16.64 60.16 0l45.227 45.227z" /> 21 | <glyph unicode="" glyph-name="dark_mode_black_24dp" d="M512 832c-212.053 0-384-171.947-384-384s171.947-384 384-384 384 171.947 384 384c0 19.627-1.707 39.253-4.267 58.027-41.813-58.453-110.080-96.427-187.733-96.427-127.147 0-230.4 103.253-230.4 230.4 0 77.227 37.973 145.92 96.427 187.733-18.773 2.56-38.4 4.267-58.027 4.267v0z" /> 22 | </font></defs></svg> -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/wwwroot/css/fonts/Awesome-Blazor-Browser-Icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/awesome-blazor-browser/889c29665008edc994b9b551d46d21a6fe848eeb/AwesomeBlazorBrowser/wwwroot/css/fonts/Awesome-Blazor-Browser-Icons.ttf -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/wwwroot/css/fonts/Awesome-Blazor-Browser-Icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/awesome-blazor-browser/889c29665008edc994b9b551d46d21a6fe848eeb/AwesomeBlazorBrowser/wwwroot/css/fonts/Awesome-Blazor-Browser-Icons.woff -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/wwwroot/css/images/ogp-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/awesome-blazor-browser/889c29665008edc994b9b551d46d21a6fe848eeb/AwesomeBlazorBrowser/wwwroot/css/images/ogp-image.png -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | body.theme-system-default, body.theme-light-mode { 2 | --default-back-color: #ffffff; 3 | --default-text-color: #24292f; 4 | --default-link-color: #0366d6; 5 | --default-link-color-light: #75b5fd; 6 | --default-border-color: #d0d7de; 7 | --quote-text-color: #6a737d; 8 | --quote-text-line-color: #dfe2e5; 9 | --header-text-line-color: #d8dee4; 10 | --weaked-text-color: #c0c0c0; 11 | --deadlink-text-color: #c0c0c0; 12 | --appbar-back-color: #24292e; 13 | --appbar-text-color: #ffffff; 14 | --searchbox-back-color: var(--appbar-back-color); 15 | --searchbox-back-color-focused: #ffffff; 16 | --searchbox-border-color: #57606a; 17 | --searchbox-text-color: #ffffff; 18 | --searchbox-text-color-focused: #000000; 19 | --footer-back-color: #e0e0e0; 20 | --footer-text-color: #606060; 21 | --scrollbar-back-color: #f1f1f1; 22 | --scrollbar-thumb-color: #a8a8a8; 23 | } 24 | 25 | @media (prefers-color-scheme: dark) { 26 | body.theme-system-default, body.theme-dark-mode { 27 | --default-back-color: #22272e; 28 | --default-text-color: #aebac6; 29 | --default-link-color: #449bf1; 30 | --default-link-color-light: #70b2ef; 31 | --default-border-color: #454c55; 32 | --header-text-line-color: #454c55; 33 | --weaked-text-color: #77838f; 34 | --deadlink-text-color: #586168; 35 | --quote-text-color: #768390; 36 | --quote-text-line-color: #444c56; 37 | --appbar-back-color: #2d333b; 38 | --appbar-text-color: var(---default-text-color); 39 | --searchbox-back-color: #22272e; 40 | --searchbox-back-color-focused: #2d333b; 41 | --searchbox-border-color: #454c55; 42 | --searchbox-text-color: #aebac6; 43 | --searchbox-text-color-focused: #aebac6; 44 | --footer-back-color: var(--appbar-back-color); 45 | --footer-text-color: var(--weaked-text-color); 46 | --scrollbar-back-color: #424242; 47 | --scrollbar-thumb-color: #7b7b7b; 48 | } 49 | } 50 | body.theme-dark-mode { 51 | --default-back-color: #22272e; 52 | --default-text-color: #aebac6; 53 | --default-link-color: #449bf1; 54 | --default-link-color-light: #70b2ef; 55 | --default-border-color: #454c55; 56 | --header-text-line-color: #454c55; 57 | --weaked-text-color: #77838f; 58 | --deadlink-text-color: #586168; 59 | --quote-text-color: #768390; 60 | --quote-text-line-color: #444c56; 61 | --appbar-back-color: #2d333b; 62 | --appbar-text-color: var(---default-text-color); 63 | --searchbox-back-color: #22272e; 64 | --searchbox-back-color-focused: #2d333b; 65 | --searchbox-border-color: #454c55; 66 | --searchbox-text-color: #aebac6; 67 | --searchbox-text-color-focused: #aebac6; 68 | --footer-back-color: var(--appbar-back-color); 69 | --footer-text-color: var(--weaked-text-color); 70 | --scrollbar-back-color: #424242; 71 | --scrollbar-thumb-color: #7b7b7b; 72 | } 73 | 74 | body, input[type=text] { 75 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji; 76 | color: var(--default-text-color); 77 | } 78 | 79 | body { 80 | font-size: 16px; 81 | line-height: 1.5; 82 | background-color: var(--default-back-color); 83 | } 84 | 85 | input[type=text] { 86 | font-size: 14px; 87 | } 88 | 89 | a { 90 | color: var(--default-link-color); 91 | text-decoration: none; 92 | } 93 | a:hover { 94 | text-decoration: underline; 95 | } 96 | a.clickable { 97 | cursor: default; 98 | user-select: none; 99 | transition: color linear 0.2s; 100 | } 101 | a.clickable:hover { 102 | color: var(--default-link-color-light); 103 | text-decoration: none; 104 | } 105 | 106 | @font-face { 107 | font-family: "Awesome-Blazor-Browser-Icons"; 108 | src: url("fonts/Awesome-Blazor-Browser-Icons.ttf?dia7uy") format("truetype"), url("fonts/Awesome-Blazor-Browser-Icons.woff?dia7uy") format("woff"), url("fonts/Awesome-Blazor-Browser-Icons.svg?dia7uy#Awesome-Blazor-Browser-Icons") format("svg"); 109 | font-weight: normal; 110 | font-style: normal; 111 | font-display: block; 112 | } 113 | .icon { 114 | /* use !important to prevent issues with browser extensions that change fonts */ 115 | font-family: "Awesome-Blazor-Browser-Icons" !important; 116 | speak: none; 117 | font-style: normal; 118 | font-weight: normal; 119 | font-variant: normal; 120 | text-transform: none; 121 | line-height: 1; 122 | /* Better Font Rendering =========== */ 123 | -webkit-font-smoothing: antialiased; 124 | -moz-osx-font-smoothing: grayscale; 125 | } 126 | 127 | .icon-checkbox-blank:before { 128 | content: "\e901"; 129 | } 130 | 131 | .icon-checkbox-checked:before { 132 | content: "\e902"; 133 | } 134 | 135 | .icon-checkbox-indeterminate:before { 136 | content: "\e904"; 137 | } 138 | 139 | .icon-expand-less:before { 140 | content: "\e900"; 141 | } 142 | 143 | .icon-expand-more:before { 144 | content: "\e903"; 145 | } 146 | 147 | .icon-link:before { 148 | content: "\e905"; 149 | } 150 | 151 | .icon-logo-blazor-large:before { 152 | content: "\e906"; 153 | } 154 | 155 | .icon-mark-github:before { 156 | content: "\e907"; 157 | } 158 | 159 | .icon-menu:before { 160 | content: "\e908"; 161 | } 162 | 163 | .icon-settings:before { 164 | content: "\e909"; 165 | } 166 | 167 | .icon-light-mode:before { 168 | content: "\e90a"; 169 | } 170 | 171 | .icon-dark-mode:before { 172 | content: "\e90b"; 173 | } 174 | 175 | .toggle-box { 176 | font-family: "Awesome-Blazor-Browser-Icons"; 177 | -webkit-font-smoothing: antialiased; 178 | -moz-osx-font-smoothing: grayscale; 179 | line-height: 1; 180 | position: relative; 181 | transition: color linear 0.2s; 182 | color: var(--default-link-color); 183 | font-size: 0; 184 | width: 24px; 185 | height: 24px; 186 | margin-right: 4px; 187 | vertical-align: middle; 188 | } 189 | .toggle-box input { 190 | display: none; 191 | } 192 | .toggle-box:hover { 193 | color: var(--default-link-color-light); 194 | } 195 | .toggle-box:after { 196 | content: ""; 197 | display: inline-block; 198 | width: 32px; 199 | height: 32px; 200 | position: absolute; 201 | border-radius: 16px; 202 | background-color: var(--default-link-color-light); 203 | z-index: -1; 204 | opacity: 0.5; 205 | transform: scale(0); 206 | top: -5px; 207 | left: -4px; 208 | transition: transform ease-out 0.1s; 209 | } 210 | .toggle-box:active:after { 211 | transform: scale(1); 212 | } 213 | .toggle-box:before { 214 | font-size: 24px; 215 | } 216 | .toggle-box.unselected:before { 217 | content: "\e901"; 218 | } 219 | .toggle-box.selected:before { 220 | content: "\e902"; 221 | } 222 | .toggle-box.selected-any:before { 223 | content: "\e904"; 224 | } 225 | 226 | #app { 227 | display: block; 228 | position: fixed; 229 | top: 0; 230 | left: 0; 231 | bottom: 0; 232 | right: 0; 233 | padding: 10px; 234 | background-color: var(--default-back-color); 235 | } 236 | #app > .header-pane { 237 | position: absolute; 238 | top: 0; 239 | left: 0; 240 | right: 0; 241 | height: 72px; 242 | } 243 | #app > .loading-mask { 244 | position: absolute; 245 | top: 72px; 246 | left: 0; 247 | bottom: 38px; 248 | right: 0; 249 | z-index: 3; 250 | background-color: var(--default-back-color); 251 | } 252 | #app > .left-pane { 253 | border-right: solid 1px var(--default-border-color); 254 | display: block; 255 | position: absolute; 256 | top: 72px; 257 | left: 0; 258 | bottom: 38px; 259 | width: 280px; 260 | transition: left ease 0.2s; 261 | z-index: 1; 262 | background-color: var(--default-back-color); 263 | } 264 | #app > .right-pane { 265 | border-left: solid 1px var(--default-border-color); 266 | display: block; 267 | position: absolute; 268 | top: 72px; 269 | right: -181px; 270 | bottom: 38px; 271 | width: 180px; 272 | transition: right ease 0.2s; 273 | z-index: 2; 274 | background-color: var(--default-back-color); 275 | } 276 | #app > .right-pane.settings-panel-expanded { 277 | right: 0; 278 | } 279 | #app > .main-mask { 280 | display: block; 281 | position: absolute; 282 | top: 72px; 283 | bottom: 38px; 284 | left: 0; 285 | right: 0; 286 | z-index: 1; 287 | background-color: #000; 288 | pointer-events: none; 289 | opacity: 0; 290 | transition: opacity ease 0.2s; 291 | } 292 | #app > .main-mask.settings-panel-expanded { 293 | opacity: 0.5; 294 | pointer-events: all; 295 | } 296 | #app > .main { 297 | display: block; 298 | position: absolute; 299 | top: 72px; 300 | left: 280px; 301 | bottom: 38px; 302 | right: 0; 303 | overflow-x: hidden; 304 | overflow-y: scroll; 305 | transition: left ease 0.2s; 306 | } 307 | #app > .main::-webkit-scrollbar { 308 | width: 12px; 309 | } 310 | #app > .main { 311 | scrollbar-width: thin; 312 | scrollbar-color: var(--scrollbar-thumb-color) var(--scrollbar-back-color); 313 | } 314 | #app > .main::-webkit-scrollbar-track { 315 | background: var(--scrollbar-back-color); 316 | } 317 | #app > .main::-webkit-scrollbar-thumb { 318 | background-color: var(--scrollbar-thumb-color); 319 | border-radius: 6px; 320 | border: solid 2px var(--scrollbar-back-color); 321 | } 322 | #app > .footer-pane { 323 | border-top: solid 1px var(--default-border-color); 324 | position: absolute; 325 | left: 0; 326 | right: 0; 327 | bottom: 0; 328 | height: 38px; 329 | } 330 | @media (max-width: 600px) { 331 | #app > .header-pane { 332 | height: 100px; 333 | } 334 | #app > .left-pane { 335 | top: 100px; 336 | left: -281px; 337 | z-index: 2; 338 | } 339 | #app > .left-pane.group-panel-expanded { 340 | left: 0; 341 | } 342 | #app > .right-pane { 343 | top: 100px; 344 | } 345 | #app > .main-mask { 346 | top: 100px; 347 | } 348 | #app > .main-mask.group-panel-expanded { 349 | opacity: 0.5; 350 | pointer-events: all; 351 | } 352 | #app > .main { 353 | top: 100px; 354 | left: 0; 355 | } 356 | #app > .loading-mask { 357 | top: 100px; 358 | } 359 | } 360 | 361 | .app-bar { 362 | background-color: var(--appbar-back-color); 363 | color: var(--appbar-text-color); 364 | position: absolute; 365 | top: 0; 366 | left: 0; 367 | bottom: 0; 368 | right: 0; 369 | display: flex; 370 | justify-content: left; 371 | align-items: center; 372 | } 373 | .app-bar > .app-text { 374 | position: relative; 375 | margin-left: 16px; 376 | padding-left: 46px; 377 | min-width: 280px; 378 | } 379 | .app-bar > .app-text .app-icon { 380 | font-family: "Awesome-Blazor-Browser-Icons"; 381 | font-size: 32px; 382 | position: absolute; 383 | top: -2px; 384 | left: 0; 385 | } 386 | .app-bar > .app-text a { 387 | color: #86bfff; 388 | } 389 | .app-bar > .app-text > .app-title { 390 | font-weight: 600; 391 | font-size: 18px; 392 | } 393 | .app-bar > .app-text > .app-description { 394 | font-size: 12px; 395 | color: var(--weaked-text-color); 396 | line-height: 14px; 397 | } 398 | .app-bar > .search-box { 399 | margin-left: 16px; 400 | margin-right: 16px; 401 | flex-grow: 1; 402 | display: flex; 403 | align-items: center; 404 | visibility: hidden; 405 | } 406 | .app-bar > .search-box.enable-search-box { 407 | visibility: visible; 408 | } 409 | .app-bar > .search-box .icon-menu, .app-bar > .search-box .icon-settings { 410 | color: var(--appbar-text-color); 411 | text-decoration: none; 412 | font-size: 24px; 413 | padding: 8px; 414 | transition: color ease 0.2s; 415 | } 416 | .app-bar > .search-box .icon-menu:hover, .app-bar > .search-box .icon-settings:hover { 417 | color: #fff; 418 | } 419 | .app-bar > .search-box .icon-menu { 420 | display: none; 421 | } 422 | .app-bar > .search-box input { 423 | background-color: var(--searchbox-back-color); 424 | flex-grow: 1; 425 | border: solid 1px var(--searchbox-border-color); 426 | height: 28px; 427 | padding-left: 10px; 428 | border-radius: 4px; 429 | color: var(--searchbox-text-color); 430 | outline: none; 431 | } 432 | .app-bar > .search-box input:focus { 433 | background-color: var(--searchbox-back-color-focused); 434 | color: var(--searchbox-text-color-focused); 435 | } 436 | @media (max-width: 600px) { 437 | .app-bar { 438 | flex-direction: column; 439 | justify-content: center; 440 | } 441 | .app-bar > .app-text > .app-description { 442 | font-size: 12px; 443 | line-height: 12px; 444 | } 445 | .app-bar > .search-box { 446 | width: 100%; 447 | flex-grow: 0; 448 | margin-top: 6px; 449 | } 450 | .app-bar > .search-box .icon-menu { 451 | display: inline-block; 452 | } 453 | } 454 | 455 | .groups-panel { 456 | position: absolute; 457 | top: 0; 458 | left: 0; 459 | bottom: 0; 460 | right: 0; 461 | } 462 | .groups-panel > .header { 463 | border-bottom: solid 1px var(--default-border-color); 464 | padding-left: 20px; 465 | height: 48px; 466 | line-height: 48px; 467 | display: flex; 468 | align-items: center; 469 | } 470 | .groups-panel > .header > .text { 471 | display: inline-block; 472 | font-weight: 600; 473 | } 474 | .groups-panel > .selector { 475 | position: absolute; 476 | top: 49px; 477 | left: 0; 478 | bottom: 0; 479 | right: 0; 480 | overflow-x: hidden; 481 | overflow-y: auto; 482 | padding: 10px 10px 10px 20px; 483 | } 484 | .groups-panel > .selector::-webkit-scrollbar { 485 | width: 12px; 486 | } 487 | .groups-panel > .selector { 488 | scrollbar-width: thin; 489 | scrollbar-color: var(--scrollbar-thumb-color) var(--scrollbar-back-color); 490 | } 491 | .groups-panel > .selector::-webkit-scrollbar-track { 492 | background: var(--scrollbar-back-color); 493 | } 494 | .groups-panel > .selector::-webkit-scrollbar-thumb { 495 | background-color: var(--scrollbar-thumb-color); 496 | border-radius: 6px; 497 | border: solid 2px var(--scrollbar-back-color); 498 | } 499 | 500 | .group-selector > .group a.link { 501 | transition: color linear 0.2s; 502 | } 503 | .group-selector > .group:not(.visible) a.link { 504 | color: var(--deadlink-text-color); 505 | cursor: default; 506 | pointer-events: none; 507 | } 508 | .group-selector > .group:not(.visible) a.link:hover { 509 | text-decoration: none; 510 | } 511 | .group-selector > .group:not(.visible) .toggle-box { 512 | color: var(--deadlink-text-color); 513 | } 514 | .group-selector > .group > .group-title { 515 | white-space: nowrap; 516 | height: 26px; 517 | display: flex; 518 | } 519 | .group-selector > .group > .group-title > .expand-box { 520 | display: inline-block; 521 | color: var(--default-text-color); 522 | text-decoration: none; 523 | transition: transform linear 0.2s; 524 | width: 26px; 525 | height: 26px; 526 | } 527 | .group-selector > .group > .group-title > .expand-box:before { 528 | display: inline-block; 529 | content: "\e903"; 530 | font-size: 18px; 531 | width: 26px; 532 | height: 26px; 533 | line-height: 26px; 534 | text-align: center; 535 | } 536 | .group-selector > .group.expanded > .group-title > .expand-box { 537 | transform: rotate(-180deg); 538 | } 539 | .group-selector .sub-group { 540 | padding-left: 10px; 541 | overflow: hidden; 542 | transition: height ease 0.2s; 543 | } 544 | 545 | .awesome-blazor-contents { 546 | margin-top: -20px; 547 | padding: 12px 12px 12px 32px; 548 | max-width: 900px; 549 | } 550 | .awesome-blazor-contents > .group { 551 | display: none; 552 | } 553 | .awesome-blazor-contents > .group.visible { 554 | display: block; 555 | } 556 | .awesome-blazor-contents > .group > .group-title { 557 | position: relative; 558 | font-size: 1.5em; 559 | font-weight: 600; 560 | color: var(--default-text-color); 561 | margin-top: 24px; 562 | margin-bottom: 16px; 563 | line-height: 1.25; 564 | padding-bottom: 0.3em; 565 | border-bottom: 1px solid var(--header-text-line-color); 566 | } 567 | .awesome-blazor-contents > .group > .group-title > .group-anchor { 568 | position: absolute; 569 | width: 22px; 570 | height: 1.5em; 571 | left: -24px; 572 | display: flex; 573 | align-items: center; 574 | text-decoration: none; 575 | } 576 | .awesome-blazor-contents > .group > .group-title > .group-anchor:after { 577 | font-family: "Awesome-Blazor-Browser-Icons"; 578 | content: "\e905"; 579 | font-size: 16px; 580 | color: var(--default-text-color); 581 | visibility: hidden; 582 | } 583 | .awesome-blazor-contents > .group > .group-title:hover > .group-anchor:after { 584 | visibility: visible; 585 | } 586 | .awesome-blazor-contents > .group blockquote { 587 | padding: 0 1em; 588 | color: var(--quote-text-color); 589 | border-left: 0.25em solid var(--quote-text-line-color); 590 | margin: 0 0 16px 0; 591 | } 592 | .awesome-blazor-contents > .group > .resources { 593 | margin-left: 10px; 594 | } 595 | .awesome-blazor-contents > .group > .resources > .resource { 596 | margin-bottom: 10px; 597 | display: none; 598 | } 599 | .awesome-blazor-contents > .group > .resources > .resource.visible { 600 | display: block; 601 | } 602 | .awesome-blazor-contents > .group > .resources > .resource > .resource-title { 603 | font-weight: 600; 604 | } 605 | .awesome-blazor-contents > .group > .resources > .resource > .resource-description { 606 | margin-left: 10px; 607 | } 608 | .awesome-blazor-contents > .group > .resources > .resource > .badges.has-badges { 609 | margin-top: 6px; 610 | margin-left: 10px; 611 | height: 24px; 612 | position: relative; 613 | } 614 | .awesome-blazor-contents > .group > .resources > .resource > .badges.has-badges > .badge.last-commit { 615 | position: absolute; 616 | top: 0; 617 | left: 92px; 618 | } 619 | .awesome-blazor-contents > .group > .resources > .resource > .resource-description img { 620 | vertical-align: middle; 621 | } 622 | .awesome-blazor-contents > .group > .resources > .resource code { 623 | font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; 624 | padding: 0.2em 0.4em; 625 | margin: 0; 626 | font-size: 85%; 627 | background-color: rgba(27, 31, 35, 0.05); 628 | border-radius: 3px; 629 | } 630 | .awesome-blazor-contents > .group > .sub-groups > .awesome-blazor-contents { 631 | padding-left: 0; 632 | } 633 | .awesome-blazor-contents > .group > .sub-groups > .awesome-blazor-contents > .group > .group-title { 634 | font-size: 1.25em; 635 | margin-top: 24px; 636 | margin-bottom: 16px; 637 | line-height: 1.25; 638 | padding-bottom: 0; 639 | border-bottom: none; 640 | } 641 | 642 | footer { 643 | background-color: var(--footer-back-color); 644 | padding: 0 20px; 645 | overflow: hidden; 646 | position: absolute; 647 | top: 0; 648 | left: 0; 649 | bottom: 0; 650 | right: 0; 651 | font-size: 13px; 652 | display: flex; 653 | align-items: center; 654 | justify-content: flex-end; 655 | } 656 | footer > .footer-item { 657 | position: relative; 658 | margin-right: 20px; 659 | color: var(--footer-text-color); 660 | height: 24px; 661 | line-height: 24px; 662 | white-space: nowrap; 663 | } 664 | footer > .footer-item.blazor { 665 | padding-left: 24px; 666 | } 667 | footer > .footer-item.blazor:after { 668 | font-family: "Awesome-Blazor-Browser-Icons"; 669 | content: "\e906"; 670 | font-size: 20px; 671 | position: absolute; 672 | top: 0; 673 | left: 0; 674 | } 675 | footer > .footer-item.github { 676 | padding-left: 24px; 677 | } 678 | footer > .footer-item.github:after { 679 | font-family: "Awesome-Blazor-Browser-Icons"; 680 | content: "\e907"; 681 | font-size: 20px; 682 | position: absolute; 683 | top: 0; 684 | left: 0; 685 | } 686 | @media (max-width: 480px) { 687 | footer { 688 | padding: 0 8px; 689 | font-size: 11.2px; 690 | } 691 | footer > .footer-item { 692 | margin-right: 8px; 693 | } 694 | footer > .footer-item:last-child { 695 | margin-right: 0; 696 | } 697 | } 698 | 699 | .settings { 700 | padding: 4px 0 0 10px; 701 | font-size: 14px; 702 | } 703 | .settings h3:first-child { 704 | margin-top: 0; 705 | } 706 | .settings h3 { 707 | margin-bottom: 0; 708 | } 709 | .settings > .theme .icon { 710 | margin-right: 4px; 711 | } 712 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/wwwroot/css/site.min.css: -------------------------------------------------------------------------------- 1 | body.theme-system-default,body.theme-light-mode{--default-back-color:#fff;--default-text-color:#24292f;--default-link-color:#0366d6;--default-link-color-light:#75b5fd;--default-border-color:#d0d7de;--quote-text-color:#6a737d;--quote-text-line-color:#dfe2e5;--header-text-line-color:#d8dee4;--weaked-text-color:#c0c0c0;--deadlink-text-color:#c0c0c0;--appbar-back-color:#24292e;--appbar-text-color:#fff;--searchbox-back-color:var(--appbar-back-color);--searchbox-back-color-focused:#fff;--searchbox-border-color:#57606a;--searchbox-text-color:#fff;--searchbox-text-color-focused:#000;--footer-back-color:#e0e0e0;--footer-text-color:#606060;--scrollbar-back-color:#f1f1f1;--scrollbar-thumb-color:#a8a8a8;}@media(prefers-color-scheme:dark){body.theme-system-default,body.theme-dark-mode{--default-back-color:#22272e;--default-text-color:#aebac6;--default-link-color:#449bf1;--default-link-color-light:#70b2ef;--default-border-color:#454c55;--header-text-line-color:#454c55;--weaked-text-color:#77838f;--deadlink-text-color:#586168;--quote-text-color:#768390;--quote-text-line-color:#444c56;--appbar-back-color:#2d333b;--appbar-text-color:var(-\2d default-text-color);--searchbox-back-color:#22272e;--searchbox-back-color-focused:#2d333b;--searchbox-border-color:#454c55;--searchbox-text-color:#aebac6;--searchbox-text-color-focused:#aebac6;--footer-back-color:var(--appbar-back-color);--footer-text-color:var(--weaked-text-color);--scrollbar-back-color:#424242;--scrollbar-thumb-color:#7b7b7b;}}body.theme-dark-mode{--default-back-color:#22272e;--default-text-color:#aebac6;--default-link-color:#449bf1;--default-link-color-light:#70b2ef;--default-border-color:#454c55;--header-text-line-color:#454c55;--weaked-text-color:#77838f;--deadlink-text-color:#586168;--quote-text-color:#768390;--quote-text-line-color:#444c56;--appbar-back-color:#2d333b;--appbar-text-color:var(-\2d default-text-color);--searchbox-back-color:#22272e;--searchbox-back-color-focused:#2d333b;--searchbox-border-color:#454c55;--searchbox-text-color:#aebac6;--searchbox-text-color-focused:#aebac6;--footer-back-color:var(--appbar-back-color);--footer-text-color:var(--weaked-text-color);--scrollbar-back-color:#424242;--scrollbar-thumb-color:#7b7b7b;}body,input[type=text]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;color:var(--default-text-color);}body{font-size:16px;line-height:1.5;background-color:var(--default-back-color);}input[type=text]{font-size:14px;}a{color:var(--default-link-color);text-decoration:none;}a:hover{text-decoration:underline;}a.clickable{cursor:default;user-select:none;transition:color linear .2s;}a.clickable:hover{color:var(--default-link-color-light);text-decoration:none;}@font-face{font-family:"Awesome-Blazor-Browser-Icons";src:url("fonts/Awesome-Blazor-Browser-Icons.ttf?dia7uy") format("truetype"),url("fonts/Awesome-Blazor-Browser-Icons.woff?dia7uy") format("woff"),url("fonts/Awesome-Blazor-Browser-Icons.svg?dia7uy#Awesome-Blazor-Browser-Icons") format("svg");font-weight:normal;font-style:normal;font-display:block;}.icon{font-family:"Awesome-Blazor-Browser-Icons"!important;speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}.icon-checkbox-blank:before{content:"";}.icon-checkbox-checked:before{content:"";}.icon-checkbox-indeterminate:before{content:"";}.icon-expand-less:before{content:"";}.icon-expand-more:before{content:"";}.icon-link:before{content:"";}.icon-logo-blazor-large:before{content:"";}.icon-mark-github:before{content:"";}.icon-menu:before{content:"";}.icon-settings:before{content:"";}.icon-light-mode:before{content:"";}.icon-dark-mode:before{content:"";}.toggle-box{font-family:"Awesome-Blazor-Browser-Icons";-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;line-height:1;position:relative;transition:color linear .2s;color:var(--default-link-color);font-size:0;width:24px;height:24px;margin-right:4px;vertical-align:middle;}.toggle-box input{display:none;}.toggle-box:hover{color:var(--default-link-color-light);}.toggle-box:after{content:"";display:inline-block;width:32px;height:32px;position:absolute;border-radius:16px;background-color:var(--default-link-color-light);z-index:-1;opacity:.5;transform:scale(0);top:-5px;left:-4px;transition:transform ease-out .1s;}.toggle-box:active:after{transform:scale(1);}.toggle-box:before{font-size:24px;}.toggle-box.unselected:before{content:"";}.toggle-box.selected:before{content:"";}.toggle-box.selected-any:before{content:"";}#app{display:block;position:fixed;top:0;left:0;bottom:0;right:0;padding:10px;background-color:var(--default-back-color);}#app>.header-pane{position:absolute;top:0;left:0;right:0;height:72px;}#app>.loading-mask{position:absolute;top:72px;left:0;bottom:38px;right:0;z-index:3;background-color:var(--default-back-color);}#app>.left-pane{border-right:solid 1px var(--default-border-color);display:block;position:absolute;top:72px;left:0;bottom:38px;width:280px;transition:left ease .2s;z-index:1;background-color:var(--default-back-color);}#app>.right-pane{border-left:solid 1px var(--default-border-color);display:block;position:absolute;top:72px;right:-181px;bottom:38px;width:180px;transition:right ease .2s;z-index:2;background-color:var(--default-back-color);}#app>.right-pane.settings-panel-expanded{right:0;}#app>.main-mask{display:block;position:absolute;top:72px;bottom:38px;left:0;right:0;z-index:1;background-color:#000;pointer-events:none;opacity:0;transition:opacity ease .2s;}#app>.main-mask.settings-panel-expanded{opacity:.5;pointer-events:all;}#app>.main{display:block;position:absolute;top:72px;left:280px;bottom:38px;right:0;overflow-x:hidden;overflow-y:scroll;transition:left ease .2s;}#app>.main::-webkit-scrollbar{width:12px;}#app>.main{scrollbar-width:thin;scrollbar-color:var(--scrollbar-thumb-color) var(--scrollbar-back-color);}#app>.main::-webkit-scrollbar-track{background:var(--scrollbar-back-color);}#app>.main::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb-color);border-radius:6px;border:solid 2px var(--scrollbar-back-color);}#app>.footer-pane{border-top:solid 1px var(--default-border-color);position:absolute;left:0;right:0;bottom:0;height:38px;}@media(max-width:600px){#app>.header-pane{height:100px;}#app>.left-pane{top:100px;left:-281px;z-index:2;}#app>.left-pane.group-panel-expanded{left:0;}#app>.right-pane{top:100px;}#app>.main-mask{top:100px;}#app>.main-mask.group-panel-expanded{opacity:.5;pointer-events:all;}#app>.main{top:100px;left:0;}#app>.loading-mask{top:100px;}}.app-bar{background-color:var(--appbar-back-color);color:var(--appbar-text-color);position:absolute;top:0;left:0;bottom:0;right:0;display:flex;justify-content:left;align-items:center;}.app-bar>.app-text{position:relative;margin-left:16px;padding-left:46px;min-width:280px;}.app-bar>.app-text .app-icon{font-family:"Awesome-Blazor-Browser-Icons";font-size:32px;position:absolute;top:-2px;left:0;}.app-bar>.app-text a{color:#86bfff;}.app-bar>.app-text>.app-title{font-weight:600;font-size:18px;}.app-bar>.app-text>.app-description{font-size:12px;color:var(--weaked-text-color);line-height:14px;}.app-bar>.search-box{margin-left:16px;margin-right:16px;flex-grow:1;display:flex;align-items:center;visibility:hidden;}.app-bar>.search-box.enable-search-box{visibility:visible;}.app-bar>.search-box .icon-menu,.app-bar>.search-box .icon-settings{color:var(--appbar-text-color);text-decoration:none;font-size:24px;padding:8px;transition:color ease .2s;}.app-bar>.search-box .icon-menu:hover,.app-bar>.search-box .icon-settings:hover{color:#fff;}.app-bar>.search-box .icon-menu{display:none;}.app-bar>.search-box input{background-color:var(--searchbox-back-color);flex-grow:1;border:solid 1px var(--searchbox-border-color);height:28px;padding-left:10px;border-radius:4px;color:var(--searchbox-text-color);outline:0;}.app-bar>.search-box input:focus{background-color:var(--searchbox-back-color-focused);color:var(--searchbox-text-color-focused);}@media(max-width:600px){.app-bar{flex-direction:column;justify-content:center;}.app-bar>.app-text>.app-description{font-size:12px;line-height:12px;}.app-bar>.search-box{width:100%;flex-grow:0;margin-top:6px;}.app-bar>.search-box .icon-menu{display:inline-block;}}.groups-panel{position:absolute;top:0;left:0;bottom:0;right:0;}.groups-panel>.header{border-bottom:solid 1px var(--default-border-color);padding-left:20px;height:48px;line-height:48px;display:flex;align-items:center;}.groups-panel>.header>.text{display:inline-block;font-weight:600;}.groups-panel>.selector{position:absolute;top:49px;left:0;bottom:0;right:0;overflow-x:hidden;overflow-y:auto;padding:10px 10px 10px 20px;}.groups-panel>.selector::-webkit-scrollbar{width:12px;}.groups-panel>.selector{scrollbar-width:thin;scrollbar-color:var(--scrollbar-thumb-color) var(--scrollbar-back-color);}.groups-panel>.selector::-webkit-scrollbar-track{background:var(--scrollbar-back-color);}.groups-panel>.selector::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb-color);border-radius:6px;border:solid 2px var(--scrollbar-back-color);}.group-selector>.group a.link{transition:color linear .2s;}.group-selector>.group:not(.visible) a.link{color:var(--deadlink-text-color);cursor:default;pointer-events:none;}.group-selector>.group:not(.visible) a.link:hover{text-decoration:none;}.group-selector>.group:not(.visible) .toggle-box{color:var(--deadlink-text-color);}.group-selector>.group>.group-title{white-space:nowrap;height:26px;display:flex;}.group-selector>.group>.group-title>.expand-box{display:inline-block;color:var(--default-text-color);text-decoration:none;transition:transform linear .2s;width:26px;height:26px;}.group-selector>.group>.group-title>.expand-box:before{display:inline-block;content:"";font-size:18px;width:26px;height:26px;line-height:26px;text-align:center;}.group-selector>.group.expanded>.group-title>.expand-box{transform:rotate(-180deg);}.group-selector .sub-group{padding-left:10px;overflow:hidden;transition:height ease .2s;}.awesome-blazor-contents{margin-top:-20px;padding:12px 12px 12px 32px;max-width:900px;}.awesome-blazor-contents>.group{display:none;}.awesome-blazor-contents>.group.visible{display:block;}.awesome-blazor-contents>.group>.group-title{position:relative;font-size:1.5em;font-weight:600;color:var(--default-text-color);margin-top:24px;margin-bottom:16px;line-height:1.25;padding-bottom:.3em;border-bottom:1px solid var(--header-text-line-color);}.awesome-blazor-contents>.group>.group-title>.group-anchor{position:absolute;width:22px;height:1.5em;left:-24px;display:flex;align-items:center;text-decoration:none;}.awesome-blazor-contents>.group>.group-title>.group-anchor:after{font-family:"Awesome-Blazor-Browser-Icons";content:"";font-size:16px;color:var(--default-text-color);visibility:hidden;}.awesome-blazor-contents>.group>.group-title:hover>.group-anchor:after{visibility:visible;}.awesome-blazor-contents>.group blockquote{padding:0 1em;color:var(--quote-text-color);border-left:.25em solid var(--quote-text-line-color);margin:0 0 16px 0;}.awesome-blazor-contents>.group>.resources{margin-left:10px;}.awesome-blazor-contents>.group>.resources>.resource{margin-bottom:10px;display:none;}.awesome-blazor-contents>.group>.resources>.resource.visible{display:block;}.awesome-blazor-contents>.group>.resources>.resource>.resource-title{font-weight:600;}.awesome-blazor-contents>.group>.resources>.resource>.resource-description{margin-left:10px;}.awesome-blazor-contents>.group>.resources>.resource>.badges.has-badges{margin-top:6px;margin-left:10px;height:24px;position:relative;}.awesome-blazor-contents>.group>.resources>.resource>.badges.has-badges>.badge.last-commit{position:absolute;top:0;left:92px;}.awesome-blazor-contents>.group>.resources>.resource>.resource-description img{vertical-align:middle;}.awesome-blazor-contents>.group>.resources>.resource code{font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;padding:.2em .4em;margin:0;font-size:85%;background-color:rgba(27,31,35,.05);border-radius:3px;}.awesome-blazor-contents>.group>.sub-groups>.awesome-blazor-contents{padding-left:0;}.awesome-blazor-contents>.group>.sub-groups>.awesome-blazor-contents>.group>.group-title{font-size:1.25em;margin-top:24px;margin-bottom:16px;line-height:1.25;padding-bottom:0;border-bottom:0;}footer{background-color:var(--footer-back-color);padding:0 20px;overflow:hidden;position:absolute;top:0;left:0;bottom:0;right:0;font-size:13px;display:flex;align-items:center;justify-content:flex-end;}footer>.footer-item{position:relative;margin-right:20px;color:var(--footer-text-color);height:24px;line-height:24px;white-space:nowrap;}footer>.footer-item.blazor{padding-left:24px;}footer>.footer-item.blazor:after{font-family:"Awesome-Blazor-Browser-Icons";content:"";font-size:20px;position:absolute;top:0;left:0;}footer>.footer-item.github{padding-left:24px;}footer>.footer-item.github:after{font-family:"Awesome-Blazor-Browser-Icons";content:"";font-size:20px;position:absolute;top:0;left:0;}@media(max-width:480px){footer{padding:0 8px;font-size:11.2px;}footer>.footer-item{margin-right:8px;}footer>.footer-item:last-child{margin-right:0;}}.settings{padding:4px 0 0 10px;font-size:14px;}.settings h3:first-child{margin-top:0;}.settings h3{margin-bottom:0;}.settings>.theme .icon{margin-right:4px;} -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsakamoto/awesome-blazor-browser/889c29665008edc994b9b551d46d21a6fe848eeb/AwesomeBlazorBrowser/wwwroot/favicon.ico -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html> 3 | 4 | <head> 5 | <meta charset="utf-8" /> 6 | <meta name="viewport" content="width=device-width" /> 7 | <base href="./" /> 8 | 9 | <script type="importmap"></script> 10 | 11 | <link rel="preload" id="webassembly" /> 12 | 13 | <title>Awesome Blazor Browser 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 |
45 |
Loading...
46 | 47 |
48 | 49 |
50 | An unhandled error has occurred. 51 | Reload 52 | 🗙 53 |
54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/wwwroot/scripts/helper.js: -------------------------------------------------------------------------------- 1 | export const scrollToAnchor = (anchorName, smooth, changeUrl) => { 2 | try { 3 | const element = document.querySelector(`a[name=${anchorName}]`); 4 | if (element !== null) { 5 | element.scrollIntoView({ behavior: smooth === true ? 'smooth' : 'auto' }); 6 | if (changeUrl === true) { 7 | const href = location.href.split('#')[0]; 8 | history.pushState(null, document.title, `${href}#${anchorName}`); 9 | } 10 | } 11 | } 12 | catch (error) { 13 | console.error(error); 14 | } 15 | }; 16 | export const getCurrentTheme = () => { 17 | return localStorage.getItem("theme") || "theme-system-default"; 18 | }; 19 | export const setCurrentTheme = (theme) => { 20 | localStorage.setItem("theme", theme); 21 | document.body.classList.remove("theme-system-default", "theme-light-mode", "theme-dark-mode"); 22 | document.body.classList.add(theme); 23 | }; 24 | export const installHashWatcher = () => { 25 | const locationHashChanged = () => { 26 | const hash = location.hash.split('#').pop() || ''; 27 | if (hash !== '') { 28 | scrollToAnchor(hash, false, false); 29 | } 30 | }; 31 | window.addEventListener("hashchange", locationHashChanged); 32 | }; 33 | -------------------------------------------------------------------------------- /AwesomeBlazorBrowser/wwwroot/scripts/theme-initializer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const theme = localStorage.getItem("theme") || "theme-system-default"; 3 | document.body.classList.add(theme); 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Awesome Blazor Browser [![github pages](https://github.com/jsakamoto/awesome-blazor-browser/workflows/github%20pages/badge.svg)](https://github.com/jsakamoto/awesome-blazor-browser/actions?query=workflow%3A%22github+pages%22) 2 | 3 | This is a Blazor WebAssembly web app for browsing the **"Awesome Blazor"** resources. 4 | 5 | [![movie](.assets/movie-001.gif)](https://jsakamoto.github.io/awesome-blazor-browser/) 6 | 7 | This Blazor WebAssembly web app fetches the "README.md" text from the ["Awesome Blazor"](https://github.com/AdrienTorris/awesome-blazor/#awesome-blazor-) GitHub repository on the fly, and parse it. 8 | 9 | ## Links 10 | 11 | - [**"Awesome Blazor Browser"**](https://jsakamoto.github.io/awesome-blazor-browser/) 12 | - Original ["Awesome Blazor" GitHub repository](https://github.com/AdrienTorris/awesome-blazor/#awesome-blazor-) 13 | 14 | ## License 15 | 16 | [GNU General Public License v3.0](LICENSE) 17 | 18 | See also: [THIRD-PARTY-NOTICES.txt](THIRD-PARTY-NOTICES.txt) -------------------------------------------------------------------------------- /THIRD-PARTY-NOTICES.txt: -------------------------------------------------------------------------------- 1 | "Awesome Blazor Browser" uses third-party libraries or other resources that may be distributed under licenses different than "Awesome Blazor Browser". 2 | 3 | 1. Markdig (https://github.com/lunet-io/markdig) 4 | 2. Octicons (https://primer.style/octicons) 5 | 3. Material icons (https://material.io/resources/icons/) 6 | 4. IcoMoon (https://icomoon.io/) 7 | 8 | %% License notice for Markdig 9 | ========================================= 10 | Copyright (c) 2018-2019, Alexandre Mutel 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without modification 14 | , are permitted provided that the following conditions are met: 15 | 16 | 1. Redistributions of source code must retain the above copyright notice, this 17 | list of conditions and the following disclaimer. 18 | 19 | 2. Redistributions in binary form must reproduce the above copyright notice, 20 | this list of conditions and the following disclaimer in the documentation 21 | and/or other materials provided with the distribution. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | ========================================= 34 | 35 | %% License notice for Octicons 36 | ========================================= 37 | MIT License 38 | 39 | Copyright (c) 2020 GitHub Inc. 40 | 41 | Permission is hereby granted, free of charge, to any person obtaining a copy 42 | of this software and associated documentation files (the "Software"), to deal 43 | in the Software without restriction, including without limitation the rights 44 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 45 | copies of the Software, and to permit persons to whom the Software is 46 | furnished to do so, subject to the following conditions: 47 | 48 | The above copyright notice and this permission notice shall be included in all 49 | copies or substantial portions of the Software. 50 | 51 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 52 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 53 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 54 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 55 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 56 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 57 | SOFTWARE. 58 | ========================================= 59 | 60 | 61 | %% License notice for Material icons 62 | ========================================= 63 | Apache License 64 | Version 2.0, January 2004 65 | http://www.apache.org/licenses/ 66 | 67 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 68 | 69 | 1. Definitions. 70 | 71 | "License" shall mean the terms and conditions for use, reproduction, 72 | and distribution as defined by Sections 1 through 9 of this document. 73 | 74 | "Licensor" shall mean the copyright owner or entity authorized by 75 | the copyright owner that is granting the License. 76 | 77 | "Legal Entity" shall mean the union of the acting entity and all 78 | other entities that control, are controlled by, or are under common 79 | control with that entity. For the purposes of this definition, 80 | "control" means (i) the power, direct or indirect, to cause the 81 | direction or management of such entity, whether by contract or 82 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 83 | outstanding shares, or (iii) beneficial ownership of such entity. 84 | 85 | "You" (or "Your") shall mean an individual or Legal Entity 86 | exercising permissions granted by this License. 87 | 88 | "Source" form shall mean the preferred form for making modifications, 89 | including but not limited to software source code, documentation 90 | source, and configuration files. 91 | 92 | "Object" form shall mean any form resulting from mechanical 93 | transformation or translation of a Source form, including but 94 | not limited to compiled object code, generated documentation, 95 | and conversions to other media types. 96 | 97 | "Work" shall mean the work of authorship, whether in Source or 98 | Object form, made available under the License, as indicated by a 99 | copyright notice that is included in or attached to the work 100 | (an example is provided in the Appendix below). 101 | 102 | "Derivative Works" shall mean any work, whether in Source or Object 103 | form, that is based on (or derived from) the Work and for which the 104 | editorial revisions, annotations, elaborations, or other modifications 105 | represent, as a whole, an original work of authorship. For the purposes 106 | of this License, Derivative Works shall not include works that remain 107 | separable from, or merely link (or bind by name) to the interfaces of, 108 | the Work and Derivative Works thereof. 109 | 110 | "Contribution" shall mean any work of authorship, including 111 | the original version of the Work and any modifications or additions 112 | to that Work or Derivative Works thereof, that is intentionally 113 | submitted to Licensor for inclusion in the Work by the copyright owner 114 | or by an individual or Legal Entity authorized to submit on behalf of 115 | the copyright owner. For the purposes of this definition, "submitted" 116 | means any form of electronic, verbal, or written communication sent 117 | to the Licensor or its representatives, including but not limited to 118 | communication on electronic mailing lists, source code control systems, 119 | and issue tracking systems that are managed by, or on behalf of, the 120 | Licensor for the purpose of discussing and improving the Work, but 121 | excluding communication that is conspicuously marked or otherwise 122 | designated in writing by the copyright owner as "Not a Contribution." 123 | 124 | "Contributor" shall mean Licensor and any individual or Legal Entity 125 | on behalf of whom a Contribution has been received by Licensor and 126 | subsequently incorporated within the Work. 127 | 128 | 2. Grant of Copyright License. Subject to the terms and conditions of 129 | this License, each Contributor hereby grants to You a perpetual, 130 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 131 | copyright license to reproduce, prepare Derivative Works of, 132 | publicly display, publicly perform, sublicense, and distribute the 133 | Work and such Derivative Works in Source or Object form. 134 | 135 | 3. Grant of Patent License. Subject to the terms and conditions of 136 | this License, each Contributor hereby grants to You a perpetual, 137 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 138 | (except as stated in this section) patent license to make, have made, 139 | use, offer to sell, sell, import, and otherwise transfer the Work, 140 | where such license applies only to those patent claims licensable 141 | by such Contributor that are necessarily infringed by their 142 | Contribution(s) alone or by combination of their Contribution(s) 143 | with the Work to which such Contribution(s) was submitted. If You 144 | institute patent litigation against any entity (including a 145 | cross-claim or counterclaim in a lawsuit) alleging that the Work 146 | or a Contribution incorporated within the Work constitutes direct 147 | or contributory patent infringement, then any patent licenses 148 | granted to You under this License for that Work shall terminate 149 | as of the date such litigation is filed. 150 | 151 | 4. Redistribution. You may reproduce and distribute copies of the 152 | Work or Derivative Works thereof in any medium, with or without 153 | modifications, and in Source or Object form, provided that You 154 | meet the following conditions: 155 | 156 | (a) You must give any other recipients of the Work or 157 | Derivative Works a copy of this License; and 158 | 159 | (b) You must cause any modified files to carry prominent notices 160 | stating that You changed the files; and 161 | 162 | (c) You must retain, in the Source form of any Derivative Works 163 | that You distribute, all copyright, patent, trademark, and 164 | attribution notices from the Source form of the Work, 165 | excluding those notices that do not pertain to any part of 166 | the Derivative Works; and 167 | 168 | (d) If the Work includes a "NOTICE" text file as part of its 169 | distribution, then any Derivative Works that You distribute must 170 | include a readable copy of the attribution notices contained 171 | within such NOTICE file, excluding those notices that do not 172 | pertain to any part of the Derivative Works, in at least one 173 | of the following places: within a NOTICE text file distributed 174 | as part of the Derivative Works; within the Source form or 175 | documentation, if provided along with the Derivative Works; or, 176 | within a display generated by the Derivative Works, if and 177 | wherever such third-party notices normally appear. The contents 178 | of the NOTICE file are for informational purposes only and 179 | do not modify the License. You may add Your own attribution 180 | notices within Derivative Works that You distribute, alongside 181 | or as an addendum to the NOTICE text from the Work, provided 182 | that such additional attribution notices cannot be construed 183 | as modifying the License. 184 | 185 | You may add Your own copyright statement to Your modifications and 186 | may provide additional or different license terms and conditions 187 | for use, reproduction, or distribution of Your modifications, or 188 | for any such Derivative Works as a whole, provided Your use, 189 | reproduction, and distribution of the Work otherwise complies with 190 | the conditions stated in this License. 191 | 192 | 5. Submission of Contributions. Unless You explicitly state otherwise, 193 | any Contribution intentionally submitted for inclusion in the Work 194 | by You to the Licensor shall be under the terms and conditions of 195 | this License, without any additional terms or conditions. 196 | Notwithstanding the above, nothing herein shall supersede or modify 197 | the terms of any separate license agreement you may have executed 198 | with Licensor regarding such Contributions. 199 | 200 | 6. Trademarks. This License does not grant permission to use the trade 201 | names, trademarks, service marks, or product names of the Licensor, 202 | except as required for reasonable and customary use in describing the 203 | origin of the Work and reproducing the content of the NOTICE file. 204 | 205 | 7. Disclaimer of Warranty. Unless required by applicable law or 206 | agreed to in writing, Licensor provides the Work (and each 207 | Contributor provides its Contributions) on an "AS IS" BASIS, 208 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 209 | implied, including, without limitation, any warranties or conditions 210 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 211 | PARTICULAR PURPOSE. You are solely responsible for determining the 212 | appropriateness of using or redistributing the Work and assume any 213 | risks associated with Your exercise of permissions under this License. 214 | 215 | 8. Limitation of Liability. In no event and under no legal theory, 216 | whether in tort (including negligence), contract, or otherwise, 217 | unless required by applicable law (such as deliberate and grossly 218 | negligent acts) or agreed to in writing, shall any Contributor be 219 | liable to You for damages, including any direct, indirect, special, 220 | incidental, or consequential damages of any character arising as a 221 | result of this License or out of the use or inability to use the 222 | Work (including but not limited to damages for loss of goodwill, 223 | work stoppage, computer failure or malfunction, or any and all 224 | other commercial damages or losses), even if such Contributor 225 | has been advised of the possibility of such damages. 226 | 227 | 9. Accepting Warranty or Additional Liability. While redistributing 228 | the Work or Derivative Works thereof, You may choose to offer, 229 | and charge a fee for, acceptance of support, warranty, indemnity, 230 | or other liability obligations and/or rights consistent with this 231 | License. However, in accepting such obligations, You may act only 232 | on Your own behalf and on Your sole responsibility, not on behalf 233 | of any other Contributor, and only if You agree to indemnify, 234 | defend, and hold each Contributor harmless for any liability 235 | incurred by, or claims asserted against, such Contributor by reason 236 | of your accepting any such warranty or additional liability. 237 | 238 | END OF TERMS AND CONDITIONS 239 | 240 | APPENDIX: How to apply the Apache License to your work. 241 | 242 | To apply the Apache License to your work, attach the following 243 | boilerplate notice, with the fields enclosed by brackets "[]" 244 | replaced with your own identifying information. (Don't include 245 | the brackets!) The text should be enclosed in the appropriate 246 | comment syntax for the file format. We also recommend that a 247 | file or class name and description of purpose be included on the 248 | same "printed page" as the copyright notice for easier 249 | identification within third-party archives. 250 | 251 | Copyright 2020 Google 252 | 253 | Licensed under the Apache License, Version 2.0 (the "License"); 254 | you may not use this file except in compliance with the License. 255 | You may obtain a copy of the License at 256 | 257 | http://www.apache.org/licenses/LICENSE-2.0 258 | 259 | Unless required by applicable law or agreed to in writing, software 260 | distributed under the License is distributed on an "AS IS" BASIS, 261 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 262 | See the License for the specific language governing permissions and 263 | limitations under the License. 264 | ========================================= 265 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "10.0.0", 4 | "allowPrerelease": true, 5 | "rollForward": "latestMinor" 6 | } 7 | } --------------------------------------------------------------------------------