diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 93ee500adf..b013825786 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,7 +3,7 @@ "hostRequirements": { "cpus": 4 }, - "onCreateCommand": "wget https://download.visualstudio.microsoft.com/download/pr/5226a5fa-8c0b-474f-b79a-8984ad7c5beb/3113ccbf789c9fd29972835f0f334b7a/dotnet-sdk-8.0.100-linux-x64.tar.gz -O $HOME/dotnet.tar.gz && export DOTNET_ROOT=$HOME/.dotnet && mkdir -p \"$DOTNET_ROOT\" && tar zxf $HOME/dotnet.tar.gz -C \"$DOTNET_ROOT\" && export PATH=$DOTNET_ROOT:$DOTNET_ROOT/tools:$PATH && dotnet dev-certs https --trust && dotnet build src/BlazorUI/Demo/Client/Web/Bit.BlazorUI.Demo.Client.Web.csproj && dotnet build src/Websites/Platform/src/Bit.Websites.Platform.Client/Bit.Websites.Platform.Client.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Websites/Sales/src/Bit.Websites.Sales.Client/Bit.Websites.Sales.Client.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Boilerplate.Client.Core.csproj -t:BeforeBuildTasks --no-restore", + "onCreateCommand": "wget https://download.visualstudio.microsoft.com/download/pr/5226a5fa-8c0b-474f-b79a-8984ad7c5beb/3113ccbf789c9fd29972835f0f334b7a/dotnet-sdk-8.0.100-linux-x64.tar.gz -O $HOME/dotnet.tar.gz && export DOTNET_ROOT=$HOME/.dotnet && mkdir -p \"$DOTNET_ROOT\" && tar zxf $HOME/dotnet.tar.gz -C \"$DOTNET_ROOT\" && export PATH=$DOTNET_ROOT:$DOTNET_ROOT/tools:$PATH && sudo dotnet workload install wasm-tools wasm-experimental && dotnet dev-certs https --trust && dotnet build src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Bit.BlazorUI.Demo.Client.Core.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Websites/Platform/src/Bit.Websites.Platform.Client/Bit.Websites.Platform.Client.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Websites/Sales/src/Bit.Websites.Sales.Client/Bit.Websites.Sales.Client.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Boilerplate.Client.Core.csproj -t:BeforeBuildTasks --no-restore", "waitFor": "onCreateCommand", "customizations": { "codespaces": { diff --git a/.github/workflows/adminpanel.cd.yml b/.github/workflows/admin-sample.cd.yml similarity index 99% rename from .github/workflows/adminpanel.cd.yml rename to .github/workflows/admin-sample.cd.yml index ca9e012b73..cdaa996df1 100644 --- a/.github/workflows/adminpanel.cd.yml +++ b/.github/workflows/admin-sample.cd.yml @@ -1,9 +1,9 @@ -name: AdminPanel CD +name: Admin Sample CD # Project templates come equipped with CI/CD for both Azure DevOps and GitHub, providing you with a hassle-free way to get started with your new project. It is important to note that you should not depend on the contents of this file. More info at https://bitplatform.dev/templates/dev-ops env: - API_SERVER_ADDRESS: 'https://adminpanel.bitplatform.dev/api/' + API_SERVER_ADDRESS: 'https://adminpanel.bitplatform.dev/' APP_SERVICE_NAME: 'bit-adminpanel' on: diff --git a/.github/workflows/bit.full.ci.yml b/.github/workflows/bit.full.ci.yml index 9191acd489..be9460a6fe 100644 --- a/.github/workflows/bit.full.ci.yml +++ b/.github/workflows/bit.full.ci.yml @@ -29,28 +29,28 @@ jobs: dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg && cd ../../../ - - name: Release build todo sample + Blazor server + sqlite database + - name: Release build todo sample + sqlite database run: | dotnet workload install maui-tizen maui-android wasm-tools wasm-experimental - dotnet new bit-bp --name TodoBPBlazorServerSqlite --database sqlite --sample todo --pipeline other - cd TodoBPBlazorServerSqlite/src/TodoBPBlazorServerSqlite.Server/ + dotnet new bit-bp --name TodoBPSqlite --database sqlite --sample todo --pipeline other + cd TodoBPSqlite/src/TodoBPSqlite.Server/ dotnet tool restore dotnet ef migrations add InitialMigration dotnet ef database update cd ../../../ - dotnet build TodoBPBlazorServerSqlite/TodoBPBlazorServerSqlite.sln -c Release -p:RunAOTCompilation=false + dotnet build TodoBPSqlite/TodoBPSqlite.sln -c Release -p:RunAOTCompilation=false - - name: Release build empty sample + Blazor hybrid + no database + - name: Release build empty sample + no database run: | - dotnet new bit-bp --name EmptyBPBlazorHybrid --database other --sample none --pipeline azure - dotnet build EmptyBPBlazorHybrid/EmptyBPBlazorHybrid.sln -c Release -p:RunAOTCompilation=false + dotnet new bit-bp --name EmptyBP --database other --sample none --pipeline azure + dotnet build EmptyBP/EmptyBP.sln -c Release -p:RunAOTCompilation=false - - name: Release build admin panel sample + Blazor webassembly + SqlServer database + - name: Release build admin panel sample + SqlServer database run: | - dotnet new bit-bp --name AdminBPBlazorWasmSqlServer --database sqlserver --sample admin --pipeline github - dotnet build AdminBPBlazorWasmSqlServer/AdminBPBlazorWasmSqlServer.sln -c Release + dotnet new bit-bp --name AdminBPSqlServer --database sqlserver --sample admin --pipeline github + dotnet build AdminBPSqlServer/AdminBPSqlServer.sln -c Release - - name: Release build bit blazor ui + bit blazor ui demo (blazor server) + butil + bswu + bup + code analyzers + source generators + - name: Release build bit blazor ui + butil + bswu + bup + code analyzers + source generators run: dotnet build src/Bit-CI-release.sln -c Release - name: Release build careers, platform, sales websites @@ -62,14 +62,9 @@ jobs: - name: Run bit blazor ui tests run: dotnet test src/BlazorUI/Bit.BlazorUI.Tests/Bit.BlazorUI.Tests.csproj -c Release - - name: Release build bit blazor ui demo - Blazor hybrid + - name: Release build bit blazor ui demo run: dotnet build src/BlazorUI/Bit.BlazorUI.sln -c Release -p:RunAOTCompilation=false - - name: Release build bit blazor ui demo - Blazor webassembly - Pwa prerendered - run: | - sed -i 's/Microsoft.NET.Sdk.Web/Microsoft.NET.Sdk.BlazorWebAssembly/g' src/BlazorUI/Demo/Client/Web/Bit.BlazorUI.Demo.Client.Web.csproj - dotnet build src/BlazorUI/Bit.BlazorUI.sln -p:BlazorMode=BlazorWebAssembly -p:WebAppDeploymentType="PwaPrerendered" -c Release -p:RunAOTCompilation=false - - name: Create projects from BlazorEmpty project template with different parameters run: | cd src/Templates/BlazorEmpty && dotnet build -c Release diff --git a/.github/workflows/blazorui.demo.cd.yml b/.github/workflows/blazorui.demo.cd.yml index a0daa9e4b4..275e0f0276 100644 --- a/.github/workflows/blazorui.demo.cd.yml +++ b/.github/workflows/blazorui.demo.cd.yml @@ -1,9 +1,6 @@ name: Blazor UI Demo CD -# Project templates come equipped with CI/CD for both Azure DevOps and GitHub, providing you with a hassle-free way to get started with your new project. It is important to note that you should not depend on the contents of this file. More info at https://bitplatform.dev/templates/dev-ops - env: - WEB_APP_DEPLOYMENT_TYPE: 'PwaPrerendered' API_SERVER_ADDRESS: 'https://components.bitplatform.dev/api/' APP_SERVICE_NAME: 'bit-components' @@ -17,42 +14,42 @@ permissions: jobs: - build_blazor_api_wasm: - name: build blazor api + web assembly + build_api_blazor: + name: build api + blazor runs-on: ubuntu-22.04 steps: - name: Checkout source code uses: actions/checkout@v3 - + - name: Setup .NET uses: actions/setup-dotnet@v3 with: global-json-file: src/global.json - - - uses: actions/setup-node@v3 - with: - node-version: 18 - + - name: Update appsettings.json api server address uses: microsoft/variable-substitution@v1 with: - files: 'src/BlazorUI/Demo/Client/Core/appsettings.json' + files: 'src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} - - name: Switch to blazor web assembly - run: sed -i 's/Microsoft.NET.Sdk.Web/Microsoft.NET.Sdk.BlazorWebAssembly/g' src/BlazorUI/Demo/Client/Web/Bit.BlazorUI.Demo.Client.Web.csproj - + - uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Install wasm run: cd src && dotnet workload install wasm-tools wasm-experimental + - name: Enable pre rendering + run: sed -i 's/public static readonly bool PrerenderEnabled = false;/public static readonly bool PrerenderEnabled = true;/g' src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/AppRenderMode.cs + - name: Generate CSS/JS files - run: dotnet build src/BlazorUI/Demo/Server/Api/Bit.BlazorUI.Demo.Server.Api.csproj -p:BlazorMode=BlazorWebAssembly -p:WebAppDeploymentType="${{ env.WEB_APP_DEPLOYMENT_TYPE }}" -c Release + run: dotnet build src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj -c Release - name: Publish - run: dotnet publish src/BlazorUI/Demo/Server/Api/Bit.BlazorUI.Demo.Server.Api.csproj -p:BlazorMode=BlazorWebAssembly -p:WebAppDeploymentType="${{ env.WEB_APP_DEPLOYMENT_TYPE }}" -c Release --self-contained -r linux-x64 -o ${{env.DOTNET_ROOT}}/server + run: dotnet publish src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj -c Release -p:PwaEnabled=true --self-contained -r linux-x64 -o ${{env.DOTNET_ROOT}}/server - name: Upload server artifact uses: actions/upload-artifact@v3 @@ -60,9 +57,9 @@ jobs: name: server-bundle path: ${{env.DOTNET_ROOT}}/server - deploy_blazor_api_wasm: - name: deploy blazor api + web assembly - needs: build_blazor_api_wasm + deploy_api_blazor: + name: deploy api + blazor + needs: build_api_blazor runs-on: ubuntu-22.04 environment: name: 'production' @@ -103,15 +100,15 @@ jobs: uses: actions/setup-dotnet@v3 with: global-json-file: src/global.json - + - uses: actions/setup-node@v3 with: node-version: 18 - + - name: Update appsettings.json api server address uses: microsoft/variable-substitution@v1 with: - files: 'src/BlazorUI/Demo/Client/Core/appsettings.json' + files: 'src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} @@ -119,16 +116,16 @@ jobs: run: cd src && dotnet workload install maui - name: Generate CSS/JS files - run: dotnet build src/BlazorUI/Demo/Client/App/Bit.BlazorUI.Demo.Client.App.csproj -p:BlazorMode=BlazorHybrid -c Release -p:WindowsPackageType=None -p:SelfContained=true -p:WindowsAppSDKSelfContained=true -p:GenerateAppxPackageOnBuild=false -p:RuntimeIdentifier=win10-x86 -p:UseRidGraph=true -f net8.0-windows10.0.19041.0 + run: dotnet build src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Bit.BlazorUI.Demo.Client.Core.csproj -c Release - name: Build exe - run: dotnet build src/BlazorUI/Demo/Client/App/Bit.BlazorUI.Demo.Client.App.csproj -p:BlazorMode=BlazorHybrid -c Release -p:WindowsPackageType=None -p:SelfContained=true -p:WindowsAppSDKSelfContained=true -p:GenerateAppxPackageOnBuild=false -p:RuntimeIdentifier=win10-x86 -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:UseRidGraph=true -f net8.0-windows10.0.19041.0 + run: dotnet build src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Bit.BlazorUI.Demo.Client.Maui.csproj -c Release -p:WindowsPackageType=None -p:SelfContained=true -p:WindowsAppSDKSelfContained=true -p:GenerateAppxPackageOnBuild=false -p:RuntimeIdentifier=win10-x86 -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:UseRidGraph=true -f net8.0-windows10.0.19041.0 - name: Upload artifact uses: actions/upload-artifact@v2 with: name: win-exe-bundle - path: src/BlazorUI/Demo/Client/App/bin/release/net8.0-windows10.0.19041.0/win10-x86 + path: src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/bin/release/net8.0-windows10.0.19041.0/win10-x86 build_blazor_hybrid_android: name: build blazor hybrid (android) @@ -151,14 +148,14 @@ jobs: - name: Extract Android signing key from env uses: timheuer/base64-to-file@v1 with: - fileDir: './src/BlazorUI/Demo/Client/App/' + fileDir: './src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/' fileName: 'BitBlazorUIDemo.keystore' encodedString: ${{ secrets.ANDROID_RELEASE_KEYSTORE_FILE_BASE64 }} - name: Update appsettings.json api server address uses: microsoft/variable-substitution@v1 with: - files: 'src/BlazorUI/Demo/Client/Core/appsettings.json' + files: 'src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} @@ -166,16 +163,56 @@ jobs: run: cd src && dotnet workload install maui-android - name: Generate CSS/JS files - run: dotnet build src/BlazorUI/Demo/Client/App/Bit.BlazorUI.Demo.Client.App.csproj -p:BlazorMode=BlazorHybrid -c Release -p:RunAOTCompilation=false -f net8.0-android + run: dotnet build src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Bit.BlazorUI.Demo.Client.Core.csproj -c Release - name: Build aab - run: dotnet build src/BlazorUI/Demo/Client/App/Bit.BlazorUI.Demo.Client.App.csproj -p:BlazorMode=BlazorHybrid -c Release -p:AndroidPackageFormat=aab -p:AndroidKeyStore=true -p:AndroidSigningKeyStore="BitBlazorUIDemo.keystore" -p:AndroidSigningKeyAlias=bitplatform -p:AndroidSigningKeyPass="${{ secrets.ANDROID_RELEASE_KEYSTORE_PASSWORD }}" -p:AndroidSigningStorePass="${{ secrets.ANDROID_RELEASE_SIGNING_PASSWORD }}" -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -f net8.0-android + run: dotnet build src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Bit.BlazorUI.Demo.Client.Maui.csproj -c Release -p:AndroidPackageFormat=aab -p:AndroidKeyStore=true -p:AndroidSigningKeyStore="BitBlazorUIDemo.keystore" -p:AndroidSigningKeyAlias=bitplatform -p:AndroidSigningKeyPass="${{ secrets.ANDROID_RELEASE_KEYSTORE_PASSWORD }}" -p:AndroidSigningStorePass="${{ secrets.ANDROID_RELEASE_SIGNING_PASSWORD }}" -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -f net8.0-android - name: Upload artifact uses: actions/upload-artifact@v2 with: name: android-bundle - path: src/BlazorUI/Demo/Client/App/bin/Release/net8.0-android/*-Signed.* + path: src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/bin/Release/net8.0-android/*-Signed.* + + build_blazor_hybrid_maccatalyst: + name: build blazor hybrid (maccatalyst) + runs-on: macos-13 + + steps: + + - name: Checkout source code + uses: actions/checkout@v3 + + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + global-json-file: src/global.json + + - uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Update appsettings.json api server address + uses: microsoft/variable-substitution@v1 + with: + files: 'src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/appsettings.json' + env: + ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} + + - name: Install maui + run: cd src && dotnet workload install maui + + - name: Generate CSS/JS files + run: dotnet build src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Bit.BlazorUI.Demo.Client.Core.csproj -c Release + + - name: Build pkg + run: dotnet build src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Bit.BlazorUI.Demo.Client.Maui.csproj -c Release -p:CreatePackage=true -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -f net8.0-maccatalyst + + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + name: mac-pkg-bundle + path: src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/bin/release/net8.0-maccatalyst/*.pkg build_blazor_hybrid_ios: name: build blazor hybrid (ios) @@ -202,7 +239,7 @@ jobs: - name: Update appsettings.json api server address uses: microsoft/variable-substitution@v1 with: - files: 'src/BlazorUI/Demo/Client/Core/appsettings.json' + files: 'src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} @@ -231,98 +268,13 @@ jobs: api-private-key: ${{ secrets.APPSTORE_API_KEY_PRIVATE_KEY }} - name: Generate CSS/JS files - run: dotnet build src/BlazorUI/Demo/Client/App/Bit.BlazorUI.Demo.Client.App.csproj -p:BlazorMode=BlazorHybrid -c Release -f net8.0-ios + run: dotnet build src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Bit.BlazorUI.Demo.Client.Core.csproj -c Release - name: Build ipa - run: dotnet publish src/BlazorUI/Demo/Client/App/Bit.BlazorUI.Demo.Client.App.csproj -p:RuntimeIdentifier=ios-arm64 -p:BlazorMode=BlazorHybrid -c Release -p:ArchiveOnBuild=true -p:CodesignKey="iPhone Distribution" -p:CodesignProvision="Bit Blazor UI Demo" -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -f net8.0-ios + run: dotnet publish src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Bit.BlazorUI.Demo.Client.Maui.csproj -p:RuntimeIdentifier=ios-arm64 -c Release -p:ArchiveOnBuild=true -p:CodesignKey="iPhone Distribution" -p:CodesignProvision="Bit Blazor UI Demo" -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -f net8.0-ios - name: Upload artifact uses: actions/upload-artifact@v2 with: name: ios-bundle - path: src/BlazorUI/Demo/Client/App/bin/release/net8.0-ios/ios-arm64/publish/*.ipa - - build_blazor_hybrid_maccatalyst: - name: build blazor hybrid (maccatalyst) - runs-on: macos-13 - - steps: - - - name: Checkout source code - uses: actions/checkout@v3 - - - name: Setup .NET - uses: actions/setup-dotnet@v3 - with: - global-json-file: src/global.json - - - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 - with: - files: 'src/BlazorUI/Demo/Client/Core/appsettings.json' - env: - ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} - - - name: Install maui - run: cd src && dotnet workload install maui - - - name: Generate CSS/JS files - run: dotnet build src/BlazorUI/Demo/Client/App/Bit.BlazorUI.Demo.Client.App.csproj -p:BlazorMode=BlazorHybrid -c Release -f net8.0-maccatalyst - - - name: Build pkg - run: dotnet build src/BlazorUI/Demo/Client/App/Bit.BlazorUI.Demo.Client.App.csproj -p:BlazorMode=BlazorHybrid -c Release -p:CreatePackage=true -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -f net8.0-maccatalyst - - - name: Upload artifact - uses: actions/upload-artifact@v2 - with: - name: mac-pkg-bundle - path: src/BlazorUI/Demo/Client/App/bin/release/net8.0-maccatalyst/*.pkg - - build_blazor_electron_linux: - name: build blazor electron (linux) - runs-on: ubuntu-22.04 - - steps: - - - name: Checkout source code - uses: actions/checkout@v3 - - - name: Setup .NET - uses: actions/setup-dotnet@v3 - with: - global-json-file: src/global.json - - - name: Setup .NET for Electron.NET - uses: actions/setup-dotnet@v3 - with: - dotnet-version: '6.x.x' - - - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 - with: - files: 'src/BlazorUI/Demo/Client/Core/appsettings.json' - env: - ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} - - - name: Switch to BlazorElectron - run: awk '//{sub(">.*BlazorElectron temp.xml && mv temp.xml src/BlazorUI/Demo/Directory.Build.props - - - name: Generate CSS/JS files - run: dotnet build src/BlazorUI/Demo/Client/Web/Bit.BlazorUI.Demo.Client.Web.csproj -c Release - - - name: Build app image - run: cd src/BlazorUI/Demo/Client/Web/ && dotnet electronize build /target linux - - - name: Upload artifact - uses: actions/upload-artifact@v2 - with: - name: linux-app-image - path: src/BlazorUI/Demo/Client/Web/bin/Desktop/linux-unpacked \ No newline at end of file + path: src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/bin/release/net8.0-ios/ios-arm64/publish/*.ipa \ No newline at end of file diff --git a/.github/workflows/nuget.org.yml b/.github/workflows/nuget.org.yml index e19d86c48c..9d60c138e9 100644 --- a/.github/workflows/nuget.org.yml +++ b/.github/workflows/nuget.org.yml @@ -87,12 +87,9 @@ jobs: - name: dotnet pack CodeAnalyzer run: dotnet pack src/CodeAnalyzers/Bit.CodeAnalyzers/Bit.CodeAnalyzers.csproj --output . --configuration Release - - - name: dotnet build SourceGenerators - run: dotnet build src/SourceGenerators/Bit.SourceGenerators/Bit.SourceGenerators.csproj -c Release -p:GeneratePackageOnBuild=false -p:WarningLevel=0 -p:RunCodeAnalysis=false - - name: dotnet pack SourceGenerators - run: dotnet pack src/SourceGenerators/Bit.SourceGenerators/Bit.SourceGenerators.csproj --output . --configuration Release + - name: build SourceGenerators nupkg file + run: dotnet build src/SourceGenerators/Bit.SourceGenerators/Bit.SourceGenerators.csproj --configuration Release - name: dotnet pack Boilerplate run: dotnet pack src/Templates/Boilerplate/Bit.Boilerplate.ProjectTemplate.csproj --output . --configuration Release @@ -101,4 +98,4 @@ jobs: run: dotnet pack src/Templates/BlazorEmpty/Bit.BlazorEmpty.ProjectTemplate.csproj --output . --configuration Release - name: dotnet nuget push - run: dotnet nuget push *.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{secrets.NUGET_ORG_API_KEY}} --skip-duplicate + run: dotnet nuget push **/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{secrets.NUGET_ORG_API_KEY}} --skip-duplicate diff --git a/.github/workflows/prerelease.nuget.org.yml b/.github/workflows/prerelease.nuget.org.yml index 0c1e73ed51..58e3f2c9f0 100644 --- a/.github/workflows/prerelease.nuget.org.yml +++ b/.github/workflows/prerelease.nuget.org.yml @@ -77,18 +77,15 @@ jobs: - name: dotnet pack CodeAnalyzer run: dotnet pack src/CodeAnalyzers/Bit.CodeAnalyzers/Bit.CodeAnalyzers.csproj --output . --configuration Release - - - name: dotnet build SourceGenerators - run: dotnet build src/SourceGenerators/Bit.SourceGenerators/Bit.SourceGenerators.csproj -c Release -p:GeneratePackageOnBuild=false -p:WarningLevel=0 -p:RunCodeAnalysis=false - - name: dotnet pack SourceGenerators - run: dotnet pack src/SourceGenerators/Bit.SourceGenerators/Bit.SourceGenerators.csproj --output . --configuration Release + - name: build SourceGenerators nupkg file + run: dotnet build src/SourceGenerators/Bit.SourceGenerators/Bit.SourceGenerators.csproj --configuration Release - name: dotnet pack Boilerplate run: dotnet pack src/Templates/Boilerplate/Bit.Boilerplate.ProjectTemplate.csproj --output . --configuration Release - name: dotnet pack BlazorEmpty run: dotnet pack src/Templates/BlazorEmpty/Bit.BlazorEmpty.ProjectTemplate.csproj --output . --configuration Release - + - name: dotnet nuget push - run: dotnet nuget push *.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{secrets.NUGET_ORG_API_KEY}} --skip-duplicate \ No newline at end of file + run: dotnet nuget push **/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{secrets.NUGET_ORG_API_KEY}} --skip-duplicate \ No newline at end of file diff --git a/.github/workflows/todotemplate.cd.yml b/.github/workflows/todo-sample.cd.yml similarity index 65% rename from .github/workflows/todotemplate.cd.yml rename to .github/workflows/todo-sample.cd.yml index 42acf86c74..34e2b52fb6 100644 --- a/.github/workflows/todotemplate.cd.yml +++ b/.github/workflows/todo-sample.cd.yml @@ -1,9 +1,9 @@ -name: TodoTemplate CD +name: Todo Sample CD # Project templates come equipped with CI/CD for both Azure DevOps and GitHub, providing you with a hassle-free way to get started with your new project. It is important to note that you should not depend on the contents of this file. More info at https://bitplatform.dev/templates/dev-ops env: - API_SERVER_ADDRESS: 'https://todo.bitplatform.dev/api/' + API_SERVER_ADDRESS: 'https://todo.bitplatform.dev/' on: workflow_dispatch: @@ -38,12 +38,12 @@ jobs: cd src/Templates/Boilerplate && dotnet build -c Release dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg - cd ../../../ && dotnet new bit-bp --name TodoTemplate --database SqlServer --sample Todo + cd ../../../ && dotnet new bit-bp --name TodoSample --database SqlServer --sample Todo - name: Update appsettings.json api server address uses: microsoft/variable-substitution@v1 with: - files: 'TodoTemplate/src/Client/TodoTemplate.Client.Core/appsettings.json' + files: 'TodoSample/src/Client/TodoSample.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} @@ -51,13 +51,13 @@ jobs: run: cd src && dotnet workload install wasm-tools wasm-experimental - name: Enable pre rendering - run: sed -i 's/public static readonly bool PrerenderEnabled = false;/public static readonly bool PrerenderEnabled = true;/g' src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AppRenderMode.cs + run: sed -i 's/public static readonly bool PrerenderEnabled = false;/public static readonly bool PrerenderEnabled = true;/g' TodoSample/src/Client/TodoSample.Client.Core/Services/AppRenderMode.cs - name: Generate CSS/JS files - run: dotnet build TodoTemplate/src/Client/TodoTemplate.Client.Core/TodoTemplate.Client.Core.csproj -t:BeforeBuildTasks --no-restore + run: dotnet build TodoSample/src/Client/TodoSample.Client.Core/TodoSample.Client.Core.csproj -t:BeforeBuildTasks --no-restore - name: Publish - run: dotnet publish TodoTemplate/src/TodoTemplate.Server/TodoTemplate.Server.csproj -c Release -p:PwaEnabled=true --self-contained -r linux-x64 -o ${{env.DOTNET_ROOT}}/server + run: dotnet publish TodoSample/src/TodoSample.Server/TodoSample.Server.csproj -c Release -p:PwaEnabled=true --self-contained -r linux-x64 -o ${{env.DOTNET_ROOT}}/server - name: Upload server artifact uses: actions/upload-artifact@v3 @@ -129,12 +129,12 @@ jobs: cd src/Templates/Boilerplate && dotnet build -c Release dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg - cd ../../../ && dotnet new bit-bp --name TodoTemplate --database SqlServer --sample Todo + cd ../../../ && dotnet new bit-bp --name TodoSample --database SqlServer --sample Todo - name: Update appsettings.json api server address uses: microsoft/variable-substitution@v1 with: - files: 'TodoTemplate/src/Client/TodoTemplate.Client.Core/appsettings.json' + files: 'TodoSample/src/Client/TodoSample.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} @@ -142,16 +142,16 @@ jobs: run: cd src && dotnet workload install maui - name: Generate CSS/JS files - run: dotnet build TodoTemplate/src/Client/TodoTemplate.Client.Core/TodoTemplate.Client.Core.csproj -t:BeforeBuildTasks --no-restore + run: dotnet build TodoSample/src/Client/TodoSample.Client.Core/TodoSample.Client.Core.csproj -t:BeforeBuildTasks --no-restore - name: Build exe - run: dotnet build TodoTemplate/src/Client/TodoTemplate.Client.Maui/TodoTemplate.Client.Maui.csproj -c Release -p:WindowsPackageType=None -p:SelfContained=true -p:WindowsAppSDKSelfContained=true -p:GenerateAppxPackageOnBuild=false -p:RuntimeIdentifier=win10-x86 -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:ApplicationTitle="TodoTemplate" -p:ApplicationId="com.bitplatform.Todo.Template" -p:UseRidGraph=true -f net8.0-windows10.0.19041.0 + run: dotnet build TodoSample/src/Client/TodoSample.Client.Maui/TodoSample.Client.Maui.csproj -c Release -p:WindowsPackageType=None -p:SelfContained=true -p:WindowsAppSDKSelfContained=true -p:GenerateAppxPackageOnBuild=false -p:RuntimeIdentifier=win10-x86 -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:ApplicationTitle="TodoSample" -p:ApplicationId="com.bitplatform.Todo.Template" -p:UseRidGraph=true -f net8.0-windows10.0.19041.0 - name: Upload artifact uses: actions/upload-artifact@v2 with: name: win-exe-bundle - path: TodoTemplate/src/Client/TodoTemplate.Client.Maui/bin/release/net8.0-windows10.0.19041.0/win10-x86 + path: TodoSample/src/Client/TodoSample.Client.Maui/bin/release/net8.0-windows10.0.19041.0/win10-x86 build_blazor_hybrid_android: name: build blazor hybrid (android) @@ -176,19 +176,19 @@ jobs: cd src/Templates/Boilerplate && dotnet build -c Release dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg - cd ../../../ && dotnet new bit-bp --name TodoTemplate --database SqlServer --sample Todo + cd ../../../ && dotnet new bit-bp --name TodoSample --database SqlServer --sample Todo - name: Extract Android signing key from env uses: timheuer/base64-to-file@v1 with: - fileDir: './TodoTemplate/src/Client/TodoTemplate.Client.Maui/' - fileName: 'TodoTemplate.keystore' + fileDir: './TodoSample/src/Client/TodoSample.Client.Maui/' + fileName: 'TodoSample.keystore' encodedString: ${{ secrets.ANDROID_RELEASE_KEYSTORE_FILE_BASE64 }} - name: Update appsettings.json api server address uses: microsoft/variable-substitution@v1 with: - files: 'TodoTemplate/src/Client/TodoTemplate.Client.Core/appsettings.json' + files: 'TodoSample/src/Client/TodoSample.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} @@ -196,16 +196,16 @@ jobs: run: cd src && dotnet workload install maui-android - name: Generate CSS/JS files - run: dotnet build TodoTemplate/src/Client/TodoTemplate.Client.Core/TodoTemplate.Client.Core.csproj -t:BeforeBuildTasks --no-restore + run: dotnet build TodoSample/src/Client/TodoSample.Client.Core/TodoSample.Client.Core.csproj -t:BeforeBuildTasks --no-restore - name: Build aab - run: dotnet build TodoTemplate/src/Client/TodoTemplate.Client.Maui/TodoTemplate.Client.Maui.csproj -c Release -p:AndroidPackageFormat=aab -p:AndroidKeyStore=true -p:AndroidSigningKeyStore="TodoTemplate.keystore" -p:AndroidSigningKeyAlias=bitplatform -p:AndroidSigningKeyPass="${{ secrets.ANDROID_RELEASE_KEYSTORE_PASSWORD }}" -p:AndroidSigningStorePass="${{ secrets.ANDROID_RELEASE_SIGNING_PASSWORD }}" -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:ApplicationTitle="TodoTemplate" -p:ApplicationId="com.bitplatform.Todo.Template" -f net8.0-android + run: dotnet build TodoSample/src/Client/TodoSample.Client.Maui/TodoSample.Client.Maui.csproj -c Release -p:AndroidPackageFormat=aab -p:AndroidKeyStore=true -p:AndroidSigningKeyStore="TodoSample.keystore" -p:AndroidSigningKeyAlias=bitplatform -p:AndroidSigningKeyPass="${{ secrets.ANDROID_RELEASE_KEYSTORE_PASSWORD }}" -p:AndroidSigningStorePass="${{ secrets.ANDROID_RELEASE_SIGNING_PASSWORD }}" -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:ApplicationTitle="TodoSample" -p:ApplicationId="com.bitplatform.Todo.Template" -f net8.0-android - name: Upload artifact uses: actions/upload-artifact@v2 with: name: android-bundle - path: TodoTemplate/src/Client/TodoTemplate.Client.Maui/bin/Release/net8.0-android/*-Signed.* + path: TodoSample/src/Client/TodoSample.Client.Maui/bin/Release/net8.0-android/*-Signed.* build_blazor_hybrid_maccatalyst: name: build blazor hybrid (maccatalyst) @@ -230,12 +230,12 @@ jobs: cd src/Templates/Boilerplate && dotnet build -c Release dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg - cd ../../../ && dotnet new bit-bp --name TodoTemplate --database SqlServer --sample Todo + cd ../../../ && dotnet new bit-bp --name TodoSample --database SqlServer --sample Todo - name: Update appsettings.json api server address uses: microsoft/variable-substitution@v1 with: - files: 'TodoTemplate/src/Client/TodoTemplate.Client.Core/appsettings.json' + files: 'TodoSample/src/Client/TodoSample.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} @@ -243,16 +243,16 @@ jobs: run: cd src && dotnet workload install maui - name: Generate CSS/JS files - run: dotnet build TodoTemplate/src/Client/TodoTemplate.Client.Core/TodoTemplate.Client.Core.csproj -t:BeforeBuildTasks --no-restore + run: dotnet build TodoSample/src/Client/TodoSample.Client.Core/TodoSample.Client.Core.csproj -t:BeforeBuildTasks --no-restore - name: Build pkg - run: dotnet build TodoTemplate/src/Client/TodoTemplate.Client.Maui/TodoTemplate.Client.Maui.csproj -c Release -p:CreatePackage=true -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:ApplicationTitle="TodoTemplate" -p:ApplicationId="com.bitplatform.Todo.Template" -f net8.0-maccatalyst + run: dotnet build TodoSample/src/Client/TodoSample.Client.Maui/TodoSample.Client.Maui.csproj -c Release -p:CreatePackage=true -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:ApplicationTitle="TodoSample" -p:ApplicationId="com.bitplatform.Todo.Template" -f net8.0-maccatalyst - name: Upload artifact uses: actions/upload-artifact@v2 with: name: mac-pkg-bundle - path: TodoTemplate/src/Client/TodoTemplate.Client.Maui/bin/release/net8.0-maccatalyst/*.pkg + path: TodoSample/src/Client/TodoSample.Client.Maui/bin/release/net8.0-maccatalyst/*.pkg build_blazor_hybrid_ios: name: build blazor hybrid (ios) @@ -281,12 +281,12 @@ jobs: cd src/Templates/Boilerplate && dotnet build -c Release dotnet pack -c Release -o . -p:ReleaseVersion=0.0.0 -p:PackageVersion=0.0.0 dotnet new install Bit.Boilerplate.0.0.0.nupkg - cd ../../../ && dotnet new bit-bp --name TodoTemplate --database SqlServer --sample Todo + cd ../../../ && dotnet new bit-bp --name TodoSample --database SqlServer --sample Todo - name: Update appsettings.json api server address uses: microsoft/variable-substitution@v1 with: - files: 'TodoTemplate/src/Client/TodoTemplate.Client.Core/appsettings.json' + files: 'TodoSample/src/Client/TodoSample.Client.Core/appsettings.json' env: ApiServerAddress: ${{ env.API_SERVER_ADDRESS }} @@ -315,13 +315,13 @@ jobs: api-private-key: ${{ secrets.APPSTORE_API_KEY_PRIVATE_KEY }} - name: Generate CSS/JS files - run: dotnet build TodoTemplate/src/Client/TodoTemplate.Client.Core/TodoTemplate.Client.Core.csproj -t:BeforeBuildTasks --no-restore + run: dotnet build TodoSample/src/Client/TodoSample.Client.Core/TodoSample.Client.Core.csproj -t:BeforeBuildTasks --no-restore - name: Build ipa - run: dotnet publish TodoTemplate/src/Client/TodoTemplate.Client.Maui/TodoTemplate.Client.Maui.csproj -p:RuntimeIdentifier=ios-arm64 -c Release -p:ArchiveOnBuild=true -p:CodesignKey="iPhone Distribution" -p:CodesignProvision="TodoTemplate" -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:ApplicationTitle="TodoTemplate" -p:ApplicationId="com.bitplatform.Todo.Template" -f net8.0-ios + run: dotnet publish TodoSample/src/Client/TodoSample.Client.Maui/TodoSample.Client.Maui.csproj -p:RuntimeIdentifier=ios-arm64 -c Release -p:ArchiveOnBuild=true -p:CodesignKey="iPhone Distribution" -p:CodesignProvision="TodoTemplate" -p:ApplicationDisplayVersion="${{ vars.APPLICATION_DISPLAY_VERSION }}" -p:ApplicationVersion="${{ vars.APPLICATION_VERSION }}" -p:ApplicationTitle="Todo" -p:ApplicationId="com.bitplatform.Todo.Template" -f net8.0-ios - name: Upload artifact uses: actions/upload-artifact@v2 with: name: ios-bundle - path: TodoTemplate/src/Client/TodoTemplate.Client.Maui/bin/release/net8.0-ios/ios-arm64/publish/*.ipa \ No newline at end of file + path: TodoSample/src/Client/TodoSample.Client.Maui/bin/release/net8.0-ios/ios-arm64/publish/*.ipa \ No newline at end of file diff --git a/.gitignore b/.gitignore index 99b68d866d..7b38da5b2f 100644 --- a/.gitignore +++ b/.gitignore @@ -263,3 +263,4 @@ _book /src/Butil/Bit.Butil/wwwroot/**/*.js custom.aprof +/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/scripts/app.js diff --git a/README.md b/README.md index ec527809b2..898fbf78e7 100644 --- a/README.md +++ b/README.md @@ -8,30 +8,28 @@ ![NuGet version](https://img.shields.io/nuget/v/bit.blazorui.svg?logo=nuget) [![Nuget downloads](https://img.shields.io/badge/packages_download-3.9M-blue.svg?logo=nuget)](https://www.nuget.org/profiles/bit-foundation) -
-
- -![image](https://user-images.githubusercontent.com/6169846/271820882-0d816266-ebd1-4c2b-a3b7-296b35248536.png) -
-Join us and start contributing to the bit platform in [hacktoberfest](https://hacktoberfest.com/). you can find the the `good first issues` [here](https://github.com/bitfoundation/bitplatform/labels/good%20first%20issue). - -

# 🧾 Introduction [bit platform](https://bitplatform.dev) is the home ❤️ for .NET developers. -Using C#, HTML, and CSS it offers a variety of dotnet project templates equipped with standard features a .NET developer needs. +Using C#, HTML, and CSS it offers a full featured dotnet project template equipped with a lot of features a .NET developer needs. With this template, one can also easily switch between different app modes: + +* **Blazor Server**: Best for fast development and debugging with hot reload. With the Blazor Server hosting model, the app is executed on the server from within an ASP.NET Core app. UI updates, event handling, and JavaScript calls are handled over a SignalR connection using the WebSockets protocol. +* **Blazor WebAssembly**: Best for SPA deployment. Blazor WebAssembly (WASM) apps run client-side in the browser on a WebAssembly-based .NET runtime. The Blazor app, its dependencies, and the .NET runtime are downloaded to the browser. The app is executed directly on the browser UI thread. UI updates and event handling occur within the same process. +* **Blazor Auto**: Blazor seamlessly combines Blazor Server and WebAssembly. This approach enhances user interaction initially through Blazor Server, while simultaneously downloading Blazor WebAssembly for subsequent visits, reducing server load. +* **Blazor Hybrid - MAUI**: Blazor can also be used to build native client apps using a hybrid approach. Hybrid apps are native apps that leverage web technologies for their functionality. In a Blazor Hybrid app, Razor components run directly in the native app (not on WebAssembly). Blazor Hybrid is on top of .NET MAUI and has access to all native features of supported platforms (Android, iOS, macOS and Windows) -With these templates, one can easily switch between different modes: +With different deployment types: -* **Blazor Server**: best for fast development and debugging with hot reload. -* **Blazor WebAssembly**: best for SPA & PWA (with or without prerendering) deployment. -* **Blazor Hybrid**: provides apps for Android, iOS, macOS, and Windows with full access to the platform's native features. -* **Blazor Electron**: provides apps for Windows, macOS, and Linux with full access to platform native features. +* **SPA**: It's referring to a Typical Single Page Application (SPA) without pre-rendering. Best for development / debugging. It is the default option. +* **PWA**: A Blazor WebAssembly app built as a Progressive Web App (PWA) uses modern browser APIs to enable many of the capabilities of a native client app, such as working offline, running in its own app window, launching from the host's operating system, receiving push notifications, and automatically updating in the background. +* **SPA-Prerendered**: Server-side rendering (SSR), is the ability of an application to contribute by displaying the web-page on the server instead of rendering it in the browser. Blazor pre-renders the requested page on the server and sends it as a static page, then later the page becomes an interactive Blazor app on the client. This behavior is intended to serve pages quickly to search engines with time-based positioning. It improves SEO. +* **PWA-Prerendered**: Almost the same as the SPA version, but with the PWA capability which reduces the toll on the server considerebly after the first render. +* **Prerender-Only**: Statically renders the component with the specified parameters without any interactivity on the client. It's recommended when the target is building a static content like a landing page. -These templates are powered by [bit BlazorUI](https://components.bitplatform.dev) components, which are super-fast 🌶 and lightweight making them the best toolbox for developing common apps. +This project template is powered by [bit BlazorUI](https://components.bitplatform.dev) components, which are super-fast 🌶 and lightweight making them the best toolbox for developing common apps.
@@ -39,11 +37,11 @@ These templates are powered by [bit BlazorUI](https://components.bitplatform.dev The following apps are our open-source projects powered by the bit platform showcasing the different capabilities of our toolchain: -| |    Web    |    iOS    | Android | Windows | macOS |  Linux  -|:-:|:--:|:--:|:--:|:--:|:--:|:--:| -| bit BlazorUI | [![Prerendered PWA](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381583-8b8eb895-80c9-4811-9641-57a5a08db163.png)](https://components.bitplatform.dev) | [![iOS app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381842-e72976ce-fd20-431d-a677-ca1ed625b83b.png)](https://apps.apple.com/us/app/bit-blazor-ui/id6450401404) | [![Android app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381958-24931682-87f6-44fc-a1c7-eecf46387005.png)](https://play.google.com/store/apps/details?id=com.bitplatform.BlazorUI.Demo) | [![Windows app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382080-9ae97fea-934c-4097-aca4-124a2aed1595.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/BlazorUIDemo-Windows.zip) | [![macOS app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382211-0d58f9ba-1a1f-4481-a0ca-b23a393cca9f.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/BlazorUIDemo-macOS.pkg) | [![Linux app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382372-59411a10-8460-4855-91e9-665f76b7011f.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/BlazorUIDemo-Linux.zip) | -| Todo | [![Prerendered PWA](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381583-8b8eb895-80c9-4811-9641-57a5a08db163.png)](https://todo.bitplatform.dev) | [![iOS app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381842-e72976ce-fd20-431d-a677-ca1ed625b83b.png)](https://apps.apple.com/us/app/bit-todotemplate/id6450611072) | [![Android app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381958-24931682-87f6-44fc-a1c7-eecf46387005.png)](https://play.google.com/store/apps/details?id=com.bitplatform.Todo.Template) | [![Windows app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382080-9ae97fea-934c-4097-aca4-124a2aed1595.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/TodoTemplate-Windows.zip) | [![macOS app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382211-0d58f9ba-1a1f-4481-a0ca-b23a393cca9f.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/TodoTemplate-macOS.pkg) | [![Linux app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382372-59411a10-8460-4855-91e9-665f76b7011f.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/TodoTemplate-Linux.zip) | -| AdminPanel | [![SPA](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251395129-71a5a79c-af74-4d4e-a0f7-ed9a15cf2e46.png)](https://adminpanel.bitplatform.dev) | [![iOS app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381842-e72976ce-fd20-431d-a677-ca1ed625b83b.png)](https://apps.apple.com/us/app/bit-adminpanel/id6450611349) | [![Android app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381958-24931682-87f6-44fc-a1c7-eecf46387005.png)](https://play.google.com/store/apps/details?id=com.bitplatform.AdminPanel.Template) | [![Windows app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382080-9ae97fea-934c-4097-aca4-124a2aed1595.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/AdminPanel-Windows.zip) | [![macOS app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382211-0d58f9ba-1a1f-4481-a0ca-b23a393cca9f.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/AdminPanel-macOS.pkg) | [![Linux app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382372-59411a10-8460-4855-91e9-665f76b7011f.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/AdminPanel-Linux.zip) | +| |    Web    |    iOS    | Android | Windows | macOS | +|:-:|:--:|:--:|:--:|:--:|:--:| +| bit BlazorUI | [![Prerendered PWA](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381583-8b8eb895-80c9-4811-9641-57a5a08db163.png)](https://components.bitplatform.dev) | [![iOS app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381842-e72976ce-fd20-431d-a677-ca1ed625b83b.png)](https://apps.apple.com/us/app/bit-blazor-ui/id6450401404) | [![Android app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381958-24931682-87f6-44fc-a1c7-eecf46387005.png)](https://play.google.com/store/apps/details?id=com.bitplatform.BlazorUI.Demo) | [![Windows app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382080-9ae97fea-934c-4097-aca4-124a2aed1595.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/BlazorUIDemo-Windows.zip) | [![macOS app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382211-0d58f9ba-1a1f-4481-a0ca-b23a393cca9f.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/BlazorUIDemo-macOS.pkg) +| Todo | [![Prerendered PWA](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381583-8b8eb895-80c9-4811-9641-57a5a08db163.png)](https://todo.bitplatform.dev) | [![iOS app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381842-e72976ce-fd20-431d-a677-ca1ed625b83b.png)](https://apps.apple.com/us/app/bit-todotemplate/id6450611072) | [![Android app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381958-24931682-87f6-44fc-a1c7-eecf46387005.png)](https://play.google.com/store/apps/details?id=com.bitplatform.Todo.Template) | [![Windows app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382080-9ae97fea-934c-4097-aca4-124a2aed1595.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/TodoTemplate-Windows.zip) | [![macOS app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382211-0d58f9ba-1a1f-4481-a0ca-b23a393cca9f.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/TodoTemplate-macOS.pkg) +| AdminPanel | [![SPA](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251395129-71a5a79c-af74-4d4e-a0f7-ed9a15cf2e46.png)](https://adminpanel.bitplatform.dev) | [![iOS app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381842-e72976ce-fd20-431d-a677-ca1ed625b83b.png)](https://apps.apple.com/us/app/bit-adminpanel/id6450611349) | [![Android app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251381958-24931682-87f6-44fc-a1c7-eecf46387005.png)](https://play.google.com/store/apps/details?id=com.bitplatform.AdminPanel.Template) | [![Windows app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382080-9ae97fea-934c-4097-aca4-124a2aed1595.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/AdminPanel-Windows.zip) | [![macOS app](https://github-production-user-asset-6210df.s3.amazonaws.com/6169846/251382211-0d58f9ba-1a1f-4481-a0ca-b23a393cca9f.png)](https://github.com/bitfoundation/bitplatform/releases/latest/download/AdminPanel-macOS.pkg) |
diff --git a/src/Bit-CI.sln b/src/Bit-CI.sln index 3e3cc17e27..c24064b27a 100644 --- a/src/Bit-CI.sln +++ b/src/Bit-CI.sln @@ -109,22 +109,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Bup.Demo.Client", "Bup\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Bup.Demo.Server", "Bup\FullDemo\Server\Bit.Bup.Demo.Server.csproj", "{FEB36A70-3C51-4C7F-949C-B8B938839740}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{110E0546-A108-4AA2-9293-F18AFD55EBDE}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{458E8540-9946-4751-B3E2-CEE7F836F05A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{06BAF737-6421-4321-9C1B-B4CEC712798E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Client.App", "BlazorUI\Demo\Client\App\Bit.BlazorUI.Demo.Client.App.csproj", "{0E3D64E7-5650-4A17-8803-3106F1BD30F0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Client.Core", "BlazorUI\Demo\Client\Core\Bit.BlazorUI.Demo.Client.Core.csproj", "{1A37BDCD-9FE4-4588-895D-EADE39B7AE27}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Client.Web", "BlazorUI\Demo\Client\Web\Bit.BlazorUI.Demo.Client.Web.csproj", "{67F6291C-1B99-45E5-B820-BE545E2F9998}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Server.Api", "BlazorUI\Demo\Server\Api\Bit.BlazorUI.Demo.Server.Api.csproj", "{18F61659-2493-45F5-AE34-F54F6C64A503}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Shared", "BlazorUI\Demo\Shared\Bit.BlazorUI.Demo.Shared.csproj", "{DCBF2669-C7EE-4C19-A71F-35134C2917C7}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Careers", "Careers", "{E70ACC14-8616-42C6-8A77-8A1123A91228}" ProjectSection(SolutionItems) = preProject Websites\Careers\.gitignore = Websites\Careers\.gitignore @@ -210,9 +194,21 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ ..\.github\workflows\platform.website.cd.yml = ..\.github\workflows\platform.website.cd.yml ..\.github\workflows\prerelease.nuget.org.yml = ..\.github\workflows\prerelease.nuget.org.yml ..\.github\workflows\sales.website.cd.yml = ..\.github\workflows\sales.website.cd.yml - ..\.github\workflows\todotemplate.cd.yml = ..\.github\workflows\todotemplate.cd.yml + ..\.github\workflows\todosample.cd.yml = ..\.github\workflows\todosample.cd.yml EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{D7242830-A91D-4729-BF2D-B1E7E141953E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Client.Core", "BlazorUI\Demo\Client\Bit.BlazorUI.Demo.Client.Core\Bit.BlazorUI.Demo.Client.Core.csproj", "{1D46B4BC-95B0-4706-AB64-69F4F66D09AA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Client.Maui", "BlazorUI\Demo\Client\Bit.BlazorUI.Demo.Client.Maui\Bit.BlazorUI.Demo.Client.Maui.csproj", "{7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Client.Web", "BlazorUI\Demo\Client\Bit.BlazorUI.Demo.Client.Web\Bit.BlazorUI.Demo.Client.Web.csproj", "{53022CD0-3145-403E-A7A0-70455D419588}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Server", "BlazorUI\Demo\Bit.BlazorUI.Demo.Server\Bit.BlazorUI.Demo.Server.csproj", "{B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Shared", "BlazorUI\Demo\Bit.BlazorUI.Demo.Shared\Bit.BlazorUI.Demo.Shared.csproj", "{79023301-B334-46E5-BD6E-313BA58E530E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -527,116 +523,6 @@ Global {FEB36A70-3C51-4C7F-949C-B8B938839740}.Release|x64.Build.0 = Release|Any CPU {FEB36A70-3C51-4C7F-949C-B8B938839740}.Release|x86.ActiveCfg = Release|Any CPU {FEB36A70-3C51-4C7F-949C-B8B938839740}.Release|x86.Build.0 = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|iPhone.Build.0 = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|iPhone.Deploy.0 = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|x64.ActiveCfg = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|x64.Build.0 = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|x64.Deploy.0 = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|x86.ActiveCfg = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|x86.Build.0 = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Debug|x86.Deploy.0 = Debug|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|Any CPU.Build.0 = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|Any CPU.Deploy.0 = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|iPhone.ActiveCfg = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|iPhone.Build.0 = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|iPhone.Deploy.0 = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|x64.ActiveCfg = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|x64.Build.0 = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|x64.Deploy.0 = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|x86.ActiveCfg = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|x86.Build.0 = Release|Any CPU - {0E3D64E7-5650-4A17-8803-3106F1BD30F0}.Release|x86.Deploy.0 = Release|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Debug|iPhone.Build.0 = Debug|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Debug|x64.ActiveCfg = Debug|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Debug|x64.Build.0 = Debug|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Debug|x86.ActiveCfg = Debug|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Debug|x86.Build.0 = Debug|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Release|Any CPU.Build.0 = Release|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Release|iPhone.ActiveCfg = Release|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Release|iPhone.Build.0 = Release|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Release|x64.ActiveCfg = Release|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Release|x64.Build.0 = Release|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Release|x86.ActiveCfg = Release|Any CPU - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27}.Release|x86.Build.0 = Release|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Debug|Any CPU.Build.0 = Debug|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Debug|iPhone.Build.0 = Debug|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Debug|x64.ActiveCfg = Debug|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Debug|x64.Build.0 = Debug|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Debug|x86.ActiveCfg = Debug|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Debug|x86.Build.0 = Debug|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Release|Any CPU.ActiveCfg = Release|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Release|Any CPU.Build.0 = Release|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Release|iPhone.ActiveCfg = Release|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Release|iPhone.Build.0 = Release|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Release|x64.ActiveCfg = Release|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Release|x64.Build.0 = Release|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Release|x86.ActiveCfg = Release|Any CPU - {67F6291C-1B99-45E5-B820-BE545E2F9998}.Release|x86.Build.0 = Release|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Debug|Any CPU.Build.0 = Debug|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Debug|iPhone.Build.0 = Debug|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Debug|x64.ActiveCfg = Debug|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Debug|x64.Build.0 = Debug|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Debug|x86.ActiveCfg = Debug|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Debug|x86.Build.0 = Debug|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Release|Any CPU.ActiveCfg = Release|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Release|Any CPU.Build.0 = Release|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Release|iPhone.ActiveCfg = Release|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Release|iPhone.Build.0 = Release|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Release|x64.ActiveCfg = Release|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Release|x64.Build.0 = Release|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Release|x86.ActiveCfg = Release|Any CPU - {18F61659-2493-45F5-AE34-F54F6C64A503}.Release|x86.Build.0 = Release|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Debug|iPhone.Build.0 = Debug|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Debug|x64.ActiveCfg = Debug|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Debug|x64.Build.0 = Debug|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Debug|x86.ActiveCfg = Debug|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Debug|x86.Build.0 = Debug|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Release|Any CPU.Build.0 = Release|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Release|iPhone.ActiveCfg = Release|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Release|iPhone.Build.0 = Release|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Release|x64.ActiveCfg = Release|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Release|x64.Build.0 = Release|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Release|x86.ActiveCfg = Release|Any CPU - {DCBF2669-C7EE-4C19-A71F-35134C2917C7}.Release|x86.Build.0 = Release|Any CPU {E09679C7-B35A-4FAB-9DB1-F03E1A0585A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E09679C7-B35A-4FAB-9DB1-F03E1A0585A9}.Debug|Any CPU.Build.0 = Debug|Any CPU {E09679C7-B35A-4FAB-9DB1-F03E1A0585A9}.Debug|iPhone.ActiveCfg = Debug|Any CPU @@ -1027,6 +913,107 @@ Global {8DD94797-A476-4E69-85B5-6B2069EBDAF5}.Release|x64.Build.0 = Release|Any CPU {8DD94797-A476-4E69-85B5-6B2069EBDAF5}.Release|x86.ActiveCfg = Release|Any CPU {8DD94797-A476-4E69-85B5-6B2069EBDAF5}.Release|x86.Build.0 = Release|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Debug|iPhone.Build.0 = Debug|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Debug|x64.ActiveCfg = Debug|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Debug|x64.Build.0 = Debug|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Debug|x86.ActiveCfg = Debug|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Debug|x86.Build.0 = Debug|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Release|Any CPU.Build.0 = Release|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Release|iPhone.ActiveCfg = Release|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Release|iPhone.Build.0 = Release|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Release|x64.ActiveCfg = Release|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Release|x64.Build.0 = Release|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Release|x86.ActiveCfg = Release|Any CPU + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA}.Release|x86.Build.0 = Release|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Debug|iPhone.Build.0 = Debug|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Debug|x64.ActiveCfg = Debug|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Debug|x64.Build.0 = Debug|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Debug|x86.ActiveCfg = Debug|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Debug|x86.Build.0 = Debug|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Release|Any CPU.Build.0 = Release|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Release|iPhone.ActiveCfg = Release|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Release|iPhone.Build.0 = Release|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Release|x64.ActiveCfg = Release|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Release|x64.Build.0 = Release|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Release|x86.ActiveCfg = Release|Any CPU + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612}.Release|x86.Build.0 = Release|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Debug|Any CPU.Build.0 = Debug|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Debug|iPhone.Build.0 = Debug|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Debug|x64.ActiveCfg = Debug|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Debug|x64.Build.0 = Debug|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Debug|x86.ActiveCfg = Debug|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Debug|x86.Build.0 = Debug|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Release|Any CPU.ActiveCfg = Release|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Release|Any CPU.Build.0 = Release|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Release|iPhone.ActiveCfg = Release|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Release|iPhone.Build.0 = Release|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Release|x64.ActiveCfg = Release|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Release|x64.Build.0 = Release|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Release|x86.ActiveCfg = Release|Any CPU + {53022CD0-3145-403E-A7A0-70455D419588}.Release|x86.Build.0 = Release|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Debug|iPhone.Build.0 = Debug|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Debug|x64.ActiveCfg = Debug|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Debug|x64.Build.0 = Debug|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Debug|x86.ActiveCfg = Debug|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Debug|x86.Build.0 = Debug|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Release|Any CPU.Build.0 = Release|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Release|iPhone.ActiveCfg = Release|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Release|iPhone.Build.0 = Release|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Release|x64.ActiveCfg = Release|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Release|x64.Build.0 = Release|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Release|x86.ActiveCfg = Release|Any CPU + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F}.Release|x86.Build.0 = Release|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Debug|iPhone.Build.0 = Debug|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Debug|x64.ActiveCfg = Debug|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Debug|x64.Build.0 = Debug|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Debug|x86.ActiveCfg = Debug|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Debug|x86.Build.0 = Debug|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Release|Any CPU.Build.0 = Release|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Release|iPhone.ActiveCfg = Release|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Release|iPhone.Build.0 = Release|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Release|x64.ActiveCfg = Release|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Release|x64.Build.0 = Release|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Release|x86.ActiveCfg = Release|Any CPU + {79023301-B334-46E5-BD6E-313BA58E530E}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1052,14 +1039,6 @@ Global {E3BD128F-554E-4875-85B8-9AC489AE49A6} = {96D8F7DE-8998-4196-AD73-B49DED4C8A38} {F0C6EF30-3D4F-4407-A605-974E5B42246E} = {E3BD128F-554E-4875-85B8-9AC489AE49A6} {FEB36A70-3C51-4C7F-949C-B8B938839740} = {E3BD128F-554E-4875-85B8-9AC489AE49A6} - {110E0546-A108-4AA2-9293-F18AFD55EBDE} = {23426B1A-CC46-4D11-B233-208A57B2BCA2} - {458E8540-9946-4751-B3E2-CEE7F836F05A} = {23426B1A-CC46-4D11-B233-208A57B2BCA2} - {06BAF737-6421-4321-9C1B-B4CEC712798E} = {23426B1A-CC46-4D11-B233-208A57B2BCA2} - {0E3D64E7-5650-4A17-8803-3106F1BD30F0} = {06BAF737-6421-4321-9C1B-B4CEC712798E} - {1A37BDCD-9FE4-4588-895D-EADE39B7AE27} = {06BAF737-6421-4321-9C1B-B4CEC712798E} - {67F6291C-1B99-45E5-B820-BE545E2F9998} = {06BAF737-6421-4321-9C1B-B4CEC712798E} - {18F61659-2493-45F5-AE34-F54F6C64A503} = {110E0546-A108-4AA2-9293-F18AFD55EBDE} - {DCBF2669-C7EE-4C19-A71F-35134C2917C7} = {458E8540-9946-4751-B3E2-CEE7F836F05A} {E70ACC14-8616-42C6-8A77-8A1123A91228} = {293480D2-1505-4C9F-B2B9-D78CA5573866} {E09679C7-B35A-4FAB-9DB1-F03E1A0585A9} = {DC165533-038F-4D71-9BA1-44CF254E116F} {C84CEAFD-DA9D-4921-AB01-BA6E063E9167} = {DC165533-038F-4D71-9BA1-44CF254E116F} @@ -1087,6 +1066,12 @@ Global {FB1E2F03-F064-4B14-9B51-A5F39AB47E9F} = {0691024C-D19B-41C0-AA76-7CBC1A875831} {8DD94797-A476-4E69-85B5-6B2069EBDAF5} = {B07A45DA-F7B7-4AF0-BE64-54DAE906FC01} {62253EDF-1D35-4184-8E2B-3CC1C419F2C0} = {EF6EF35E-9612-4B2A-8BFE-41234BFCAD78} + {D7242830-A91D-4729-BF2D-B1E7E141953E} = {23426B1A-CC46-4D11-B233-208A57B2BCA2} + {1D46B4BC-95B0-4706-AB64-69F4F66D09AA} = {D7242830-A91D-4729-BF2D-B1E7E141953E} + {7667FE62-07E4-4BF7-BCD3-A3F8FBDFE612} = {D7242830-A91D-4729-BF2D-B1E7E141953E} + {53022CD0-3145-403E-A7A0-70455D419588} = {D7242830-A91D-4729-BF2D-B1E7E141953E} + {B61B811C-5D2B-4DF5-9D7B-212F4B464E3F} = {23426B1A-CC46-4D11-B233-208A57B2BCA2} + {79023301-B334-46E5-BD6E-313BA58E530E} = {23426B1A-CC46-4D11-B233-208A57B2BCA2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DA107107-478F-477A-872B-787CEA7DD9B8} diff --git a/src/Bit.Build.props b/src/Bit.Build.props index fb24a7f549..5d012d2d41 100644 --- a/src/Bit.Build.props +++ b/src/Bit.Build.props @@ -25,7 +25,7 @@ https://github.com/bitfoundation/bitplatform https://avatars.githubusercontent.com/u/22663390 - 8.2.0 + 8.3.0 https://github.com/bitfoundation/bitplatform/releases/tag/v-$(ReleaseVersion) $(ReleaseVersion) diff --git a/src/BlazorUI/Bit.BlazorUI.sln b/src/BlazorUI/Bit.BlazorUI.sln index 6da10e4968..92b6612fdd 100644 --- a/src/BlazorUI/Bit.BlazorUI.sln +++ b/src/BlazorUI/Bit.BlazorUI.sln @@ -27,25 +27,21 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Demo", "Demo", "{0EB8B659-F EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{90459635-8633-482F-9A01-AD07AC033B99}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{32A24596-2D20-47D1-9C75-9E42CB592D11}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{C16B7050-0842-4A34-89EE-1A41A5BE8651}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Shared", "Demo\Shared\Bit.BlazorUI.Demo.Shared.csproj", "{524D1133-5940-416E-81C2-7AF2469B935E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Extras", "Bit.BlazorUI.Extras\Bit.BlazorUI.Extras.csproj", "{E2D0BBB0-9317-47EF-83F6-F50F452C6A26}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Server.Api", "Demo\Server\Api\Bit.BlazorUI.Demo.Server.Api.csproj", "{FCC7E125-43F1-44D4-8193-817E4698F5CE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Assets", "Bit.BlazorUI.Assets\Bit.BlazorUI.Assets.csproj", "{3F41403F-A9A3-45CE-81E2-3FAFCEDD9509}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Client.App", "Demo\Client\App\Bit.BlazorUI.Demo.Client.App.csproj", "{65DEE16F-22DF-4795-A219-87E120FC59F1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Icons", "Bit.BlazorUI.Icons\Bit.BlazorUI.Icons.csproj", "{605C139C-D6F4-446A-AB28-A5C713A07043}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Client.Core", "Demo\Client\Core\Bit.BlazorUI.Demo.Client.Core.csproj", "{A0661277-A62E-4358-A61B-E4EE6AF3C976}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Client.Core", "Demo\Client\Bit.BlazorUI.Demo.Client.Core\Bit.BlazorUI.Demo.Client.Core.csproj", "{F23B7419-BFD6-4DD5-98EB-B5240978D94D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Client.Web", "Demo\Client\Web\Bit.BlazorUI.Demo.Client.Web.csproj", "{87AD691F-4EC9-493E-BC07-D4CBEC9050E5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Client.Maui", "Demo\Client\Bit.BlazorUI.Demo.Client.Maui\Bit.BlazorUI.Demo.Client.Maui.csproj", "{BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Extras", "Bit.BlazorUI.Extras\Bit.BlazorUI.Extras.csproj", "{E2D0BBB0-9317-47EF-83F6-F50F452C6A26}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Client.Web", "Demo\Client\Bit.BlazorUI.Demo.Client.Web\Bit.BlazorUI.Demo.Client.Web.csproj", "{8312F98B-4B14-40C2-BDC7-BD217B96EC67}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Assets", "Bit.BlazorUI.Assets\Bit.BlazorUI.Assets.csproj", "{3F41403F-A9A3-45CE-81E2-3FAFCEDD9509}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Server", "Demo\Bit.BlazorUI.Demo.Server\Bit.BlazorUI.Demo.Server.csproj", "{894136EE-5383-42CC-AE46-345418A474F2}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Icons", "Bit.BlazorUI.Icons\Bit.BlazorUI.Icons.csproj", "{605C139C-D6F4-446A-AB28-A5C713A07043}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Demo.Shared", "Demo\Bit.BlazorUI.Demo.Shared\Bit.BlazorUI.Demo.Shared.csproj", "{820024D2-10D8-4CD7-9C4A-42F38EEBCC55}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -121,116 +117,6 @@ Global {050CE6DE-ECAF-4C7E-A7C8-DB8D977C98C8}.Release|x64.Build.0 = Release|Any CPU {050CE6DE-ECAF-4C7E-A7C8-DB8D977C98C8}.Release|x86.ActiveCfg = Release|Any CPU {050CE6DE-ECAF-4C7E-A7C8-DB8D977C98C8}.Release|x86.Build.0 = Release|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Debug|iPhone.Build.0 = Debug|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Debug|x64.ActiveCfg = Debug|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Debug|x64.Build.0 = Debug|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Debug|x86.ActiveCfg = Debug|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Debug|x86.Build.0 = Debug|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Release|Any CPU.Build.0 = Release|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Release|iPhone.ActiveCfg = Release|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Release|iPhone.Build.0 = Release|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Release|x64.ActiveCfg = Release|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Release|x64.Build.0 = Release|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Release|x86.ActiveCfg = Release|Any CPU - {524D1133-5940-416E-81C2-7AF2469B935E}.Release|x86.Build.0 = Release|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Debug|iPhone.Build.0 = Debug|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Debug|x64.ActiveCfg = Debug|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Debug|x64.Build.0 = Debug|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Debug|x86.ActiveCfg = Debug|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Debug|x86.Build.0 = Debug|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Release|Any CPU.Build.0 = Release|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Release|iPhone.ActiveCfg = Release|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Release|iPhone.Build.0 = Release|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Release|x64.ActiveCfg = Release|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Release|x64.Build.0 = Release|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Release|x86.ActiveCfg = Release|Any CPU - {FCC7E125-43F1-44D4-8193-817E4698F5CE}.Release|x86.Build.0 = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|iPhone.Build.0 = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|iPhone.Deploy.0 = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|x64.ActiveCfg = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|x64.Build.0 = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|x64.Deploy.0 = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|x86.ActiveCfg = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|x86.Build.0 = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Debug|x86.Deploy.0 = Debug|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|Any CPU.Build.0 = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|Any CPU.Deploy.0 = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|iPhone.ActiveCfg = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|iPhone.Build.0 = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|iPhone.Deploy.0 = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|x64.ActiveCfg = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|x64.Build.0 = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|x64.Deploy.0 = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|x86.ActiveCfg = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|x86.Build.0 = Release|Any CPU - {65DEE16F-22DF-4795-A219-87E120FC59F1}.Release|x86.Deploy.0 = Release|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Debug|iPhone.Build.0 = Debug|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Debug|x64.ActiveCfg = Debug|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Debug|x64.Build.0 = Debug|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Debug|x86.ActiveCfg = Debug|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Debug|x86.Build.0 = Debug|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Release|Any CPU.Build.0 = Release|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Release|iPhone.ActiveCfg = Release|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Release|iPhone.Build.0 = Release|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Release|x64.ActiveCfg = Release|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Release|x64.Build.0 = Release|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Release|x86.ActiveCfg = Release|Any CPU - {A0661277-A62E-4358-A61B-E4EE6AF3C976}.Release|x86.Build.0 = Release|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Debug|iPhone.Build.0 = Debug|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Debug|x64.ActiveCfg = Debug|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Debug|x64.Build.0 = Debug|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Debug|x86.ActiveCfg = Debug|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Debug|x86.Build.0 = Debug|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Release|Any CPU.Build.0 = Release|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Release|iPhone.ActiveCfg = Release|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Release|iPhone.Build.0 = Release|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Release|x64.ActiveCfg = Release|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Release|x64.Build.0 = Release|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Release|x86.ActiveCfg = Release|Any CPU - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5}.Release|x86.Build.0 = Release|Any CPU {E2D0BBB0-9317-47EF-83F6-F50F452C6A26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E2D0BBB0-9317-47EF-83F6-F50F452C6A26}.Debug|Any CPU.Build.0 = Debug|Any CPU {E2D0BBB0-9317-47EF-83F6-F50F452C6A26}.Debug|iPhone.ActiveCfg = Debug|Any CPU @@ -291,19 +177,127 @@ Global {605C139C-D6F4-446A-AB28-A5C713A07043}.Release|x64.Build.0 = Release|Any CPU {605C139C-D6F4-446A-AB28-A5C713A07043}.Release|x86.ActiveCfg = Release|Any CPU {605C139C-D6F4-446A-AB28-A5C713A07043}.Release|x86.Build.0 = Release|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Debug|iPhone.Build.0 = Debug|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Debug|x64.ActiveCfg = Debug|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Debug|x64.Build.0 = Debug|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Debug|x86.ActiveCfg = Debug|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Debug|x86.Build.0 = Debug|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Release|Any CPU.Build.0 = Release|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Release|iPhone.ActiveCfg = Release|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Release|iPhone.Build.0 = Release|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Release|x64.ActiveCfg = Release|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Release|x64.Build.0 = Release|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Release|x86.ActiveCfg = Release|Any CPU + {F23B7419-BFD6-4DD5-98EB-B5240978D94D}.Release|x86.Build.0 = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|iPhone.Build.0 = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|iPhone.Deploy.0 = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|x64.ActiveCfg = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|x64.Build.0 = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|x64.Deploy.0 = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|x86.ActiveCfg = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|x86.Build.0 = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Debug|x86.Deploy.0 = Debug|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|Any CPU.Build.0 = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|Any CPU.Deploy.0 = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|iPhone.ActiveCfg = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|iPhone.Build.0 = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|iPhone.Deploy.0 = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|x64.ActiveCfg = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|x64.Build.0 = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|x64.Deploy.0 = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|x86.ActiveCfg = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|x86.Build.0 = Release|Any CPU + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD}.Release|x86.Deploy.0 = Release|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Debug|iPhone.Build.0 = Debug|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Debug|x64.ActiveCfg = Debug|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Debug|x64.Build.0 = Debug|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Debug|x86.ActiveCfg = Debug|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Debug|x86.Build.0 = Debug|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Release|Any CPU.Build.0 = Release|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Release|iPhone.ActiveCfg = Release|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Release|iPhone.Build.0 = Release|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Release|x64.ActiveCfg = Release|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Release|x64.Build.0 = Release|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Release|x86.ActiveCfg = Release|Any CPU + {8312F98B-4B14-40C2-BDC7-BD217B96EC67}.Release|x86.Build.0 = Release|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Debug|iPhone.Build.0 = Debug|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Debug|x64.ActiveCfg = Debug|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Debug|x64.Build.0 = Debug|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Debug|x86.ActiveCfg = Debug|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Debug|x86.Build.0 = Debug|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Release|Any CPU.Build.0 = Release|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Release|iPhone.ActiveCfg = Release|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Release|iPhone.Build.0 = Release|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Release|x64.ActiveCfg = Release|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Release|x64.Build.0 = Release|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Release|x86.ActiveCfg = Release|Any CPU + {894136EE-5383-42CC-AE46-345418A474F2}.Release|x86.Build.0 = Release|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Debug|Any CPU.Build.0 = Debug|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Debug|iPhone.Build.0 = Debug|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Debug|x64.ActiveCfg = Debug|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Debug|x64.Build.0 = Debug|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Debug|x86.ActiveCfg = Debug|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Debug|x86.Build.0 = Debug|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Release|Any CPU.ActiveCfg = Release|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Release|Any CPU.Build.0 = Release|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Release|iPhone.ActiveCfg = Release|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Release|iPhone.Build.0 = Release|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Release|x64.ActiveCfg = Release|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Release|x64.Build.0 = Release|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Release|x86.ActiveCfg = Release|Any CPU + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {90459635-8633-482F-9A01-AD07AC033B99} = {0EB8B659-FE79-46B6-A87A-3EAC7A5AE321} - {32A24596-2D20-47D1-9C75-9E42CB592D11} = {0EB8B659-FE79-46B6-A87A-3EAC7A5AE321} - {C16B7050-0842-4A34-89EE-1A41A5BE8651} = {0EB8B659-FE79-46B6-A87A-3EAC7A5AE321} - {524D1133-5940-416E-81C2-7AF2469B935E} = {C16B7050-0842-4A34-89EE-1A41A5BE8651} - {FCC7E125-43F1-44D4-8193-817E4698F5CE} = {32A24596-2D20-47D1-9C75-9E42CB592D11} - {65DEE16F-22DF-4795-A219-87E120FC59F1} = {90459635-8633-482F-9A01-AD07AC033B99} - {A0661277-A62E-4358-A61B-E4EE6AF3C976} = {90459635-8633-482F-9A01-AD07AC033B99} - {87AD691F-4EC9-493E-BC07-D4CBEC9050E5} = {90459635-8633-482F-9A01-AD07AC033B99} + {F23B7419-BFD6-4DD5-98EB-B5240978D94D} = {90459635-8633-482F-9A01-AD07AC033B99} + {BCBD77AD-74D1-4F5F-9673-C68D593B4DDD} = {90459635-8633-482F-9A01-AD07AC033B99} + {8312F98B-4B14-40C2-BDC7-BD217B96EC67} = {90459635-8633-482F-9A01-AD07AC033B99} + {894136EE-5383-42CC-AE46-345418A474F2} = {0EB8B659-FE79-46B6-A87A-3EAC7A5AE321} + {820024D2-10D8-4CD7-9C4A-42F38EEBCC55} = {0EB8B659-FE79-46B6-A87A-3EAC7A5AE321} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DA107107-478F-477A-872B-787CEA7DD9B8} diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmer.razor b/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmer.razor new file mode 100644 index 0000000000..0d5e6f9999 --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmer.razor @@ -0,0 +1,26 @@ +@namespace Bit.BlazorUI +@inherits BitComponentBase + +
+ @if (IsDataLoaded) + { +
+ @(ChildContent ?? Content) +
+ } + else + { + @if (ShimmerTemplate is not null) + { + @ShimmerTemplate + } + else + { +
+
+
+ } + } +
\ No newline at end of file diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmer.razor.cs b/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmer.razor.cs new file mode 100644 index 0000000000..b6f5d7814d --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmer.razor.cs @@ -0,0 +1,112 @@ +namespace Bit.BlazorUI; + +public partial class BitShimmer +{ + private BitShimmerShape shape = BitShimmerShape.Line; + private BitShimmerAnimation animtaion = BitShimmerAnimation.Wave; + + + + /// + /// The animation of the shimmer. + /// + [Parameter] + public BitShimmerAnimation Animation + { + get => animtaion; + set + { + if (animtaion == value) return; + + animtaion = value; + ClassBuilder.Reset(); + } + } + + /// + /// Child content of component, the content that the shimmer will apply to. + /// + [Parameter] public RenderFragment? ChildContent { get; set; } + + /// + /// Custom CSS classes for different parts of the BitShimmer. + /// + [Parameter] public BitShimmerClassStyles? Classes { get; set; } + + /// + /// Alias of ChildContent. + /// + [Parameter] public RenderFragment? Content { get; set; } + + /// + /// The shimmer height value. + /// + [Parameter] public string? Height { get; set; } + + /// + /// Controls when the shimmer is swapped with actual data through an animated transition. + /// + [Parameter] public bool IsDataLoaded { get; set; } + + /// + /// The shape of the shimmer. + /// + [Parameter] public BitShimmerShape Shape + { + get => shape; + set + { + if (shape == value) return; + + shape = value; + ClassBuilder.Reset(); + } + } + + /// + /// The template of the shimmer. + /// + [Parameter] public RenderFragment? ShimmerTemplate { get; set; } + + /// + /// Custom CSS styles for different parts of the BitShimmer. + /// + [Parameter] public BitShimmerClassStyles? Styles { get; set; } + + /// + /// The shimmer width value. + /// + [Parameter] public string? Width { get; set; } + + + protected override string RootElementClass => "bit-smr"; + + protected override void RegisterCssClasses() + { + ClassBuilder.Register(() => Classes?.Root); + } + + protected override void RegisterCssStyles() + { + StyleBuilder.Register(() => Styles?.Root); + + StyleBuilder.Register(() => Width.HasValue() ? $"width:{Width}" : string.Empty); + StyleBuilder.Register(() => Height.HasValue() ? $"height:{Height}" : string.Empty); + } + + + private string GetShapesClass() => Shape switch + { + BitShimmerShape.Line => "bit-smr-lin", + BitShimmerShape.Circle => "bit-smr-crl", + BitShimmerShape.Rectangle => "bit-smr-rct", + _ => "bit-smr-lin" + }; + + private string GetAnimationClass() => Animation switch + { + BitShimmerAnimation.Wave => "bit-smr-wav", + BitShimmerAnimation.Pulse => "bit-smr-pul", + _ => "bit-smr-wav" + }; +} diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmer.scss b/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmer.scss new file mode 100644 index 0000000000..9aea29366f --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmer.scss @@ -0,0 +1,79 @@ +@import "../../Styles/functions.scss"; + +.bit-smr { + display: block; + + @keyframes shimmer-wave-anim { + 0% { + transform: translateX(-100%); + } + + 100% { + transform: translateX(100%); + } + } + + @keyframes shimmer-pulse-anim { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } + } + + @keyframes shimmer-opacity-anim { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } + } +} + +.bit-smr-cnt { + animation-fill-mode: both; + animation-duration: 0.367s; + animation-timing-function: ease; + animation-name: shimmer-opacity-anim; +} + +.bit-smr-wrp { + height: 100%; + overflow: hidden; + position: relative; + animation-fill-mode: both; + animation-duration: 0.367s; + animation-timing-function: ease; + animation-name: shimmer-opacity-anim; + background-color: $color-background-secondary; +} + +.bit-smr-lin { + border-radius: spacing(0.5); +} + +.bit-smr-crl { + aspect-ratio: 1; + border-radius: 50%; +} + +.bit-smr-anm { + inset: 0; + overflow: hidden; + position: absolute; + background: $color-background-disabled; +} + +.bit-smr-wav { + transform: translateX(-100%); + animation: shimmer-wave-anim 1.6s linear 0.5s infinite; + background: linear-gradient(90deg, transparent, $color-background-disabled, transparent); +} + +.bit-smr-pul { + animation: shimmer-pulse-anim 1.5s ease-in-out 0.5s infinite; +} diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmerAnimation.cs b/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmerAnimation.cs new file mode 100644 index 0000000000..7737c435f6 --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmerAnimation.cs @@ -0,0 +1,7 @@ +namespace Bit.BlazorUI; + +public enum BitShimmerAnimation +{ + Wave, + Pulse +} diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmerClassStyles.cs b/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmerClassStyles.cs new file mode 100644 index 0000000000..1f98da4f78 --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmerClassStyles.cs @@ -0,0 +1,24 @@ +namespace Bit.BlazorUI; + +public class BitShimmerClassStyles +{ + /// + /// Custom CSS classes/styles for the root element of the BitShimmer. + /// + public string? Root { get; set; } + + /// + /// Custom CSS classes/styles for the content of the BitShimmer. + /// + public string? Content { get; set; } + + /// + /// Custom CSS classes/styles for the shimmer wrapper of the BitShimmer. + /// + public string? ShimmerWrapper { get; set; } + + /// + /// Custom CSS classes/styles for the shimmer of the BitShimmer. + /// + public string? Shimmer { get; set; } +} diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmerShape.cs b/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmerShape.cs new file mode 100644 index 0000000000..e9706f01f2 --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI/Components/Shimmer/BitShimmerShape.cs @@ -0,0 +1,8 @@ +namespace Bit.BlazorUI; + +public enum BitShimmerShape +{ + Line, + Circle, + Rectangle +} diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltip.razor b/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltip.razor new file mode 100644 index 0000000000..398b171c12 --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltip.razor @@ -0,0 +1,32 @@ +@namespace Bit.BlazorUI +@inherits BitComponentBase + +
+ + @(Anchor ?? ChildContent) + +
+
+ @if (Template is not null) + { + @Template + } + else + { + @Text + } +
+ @if (HideArrow is false) + { +
+ } +
+
\ No newline at end of file diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltip.razor.cs b/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltip.razor.cs new file mode 100644 index 0000000000..ee84a31515 --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltip.razor.cs @@ -0,0 +1,250 @@ +using System.Text; + +namespace Bit.BlazorUI; + +public partial class BitTooltip +{ + private bool IsShownHasBeenSet; + + private CancellationTokenSource? _showDelayTokenSource = new CancellationTokenSource(); + private CancellationTokenSource? _hideDelayTokenSource = new CancellationTokenSource(); + + private bool isShown; + private BitTooltipPosition tooltipPosition = BitTooltipPosition.Top; + + + + /// + /// Alias of ChildContent. + /// + [Parameter] public RenderFragment? Anchor { get; set; } + + /// + /// The content inside of tooltip tag, It can be Any custom tag or a text. + /// + [Parameter] public RenderFragment? ChildContent { get; set; } + + /// + /// Custom CSS classes for different parts of the BitTooltip. + /// + [Parameter] public BitTooltipClassStyles? Classes { get; set; } + + /// + /// Default value of the IsShown. + /// + [Parameter] public bool? DefaultIsShown { get; set; } + + /// + /// Hides the arrow of tooltip. + /// + [Parameter] public bool HideArrow { get; set; } + + /// + /// Delay (in milliseconds) before hiding the tooltip. + /// + [Parameter] public int HideDelay { get; set; } = 0; + + /// + /// The visibility state of the tooltip. + /// + [Parameter] + public bool IsShown + { + get => isShown; + set + { + if (isShown == value) return; + + isShown = value; + _ = IsShownChanged.InvokeAsync(isShown); + } + } + + [Parameter] public EventCallback IsShownChanged { get; set; } + + /// + /// The position of tooltip around its anchor. + /// + [Parameter] + public BitTooltipPosition Position + { + get => tooltipPosition; + set + { + if (tooltipPosition == value) return; + + tooltipPosition = value; + ClassBuilder.Reset(); + } + } + + /// + /// The content you want inside the tooltip. + /// + [Parameter] public RenderFragment? Template { get; set; } + + /// + /// The text of tooltip to show. + /// + [Parameter] public string? Text { get; set; } + + /// + /// Determines shows tooltip on click. + /// + [Parameter] public bool ShowOnClick { get; set; } + + /// + /// Delay (in milliseconds) before showing the tooltip. + /// + [Parameter] public int ShowDelay { get; set; } = 0; + + /// + /// Determines shows tooltip on focus. + /// + [Parameter] public bool ShowOnFocus { get; set; } + + /// + /// Determines shows tooltip on hover. + /// + [Parameter] public bool ShowOnHover { get; set; } = true; + + /// + /// Custom CSS styles for different parts of the BitTooltip. + /// + [Parameter] public BitTooltipClassStyles? Styles { get; set; } + + + protected override string RootElementClass => "bit-ttp"; + + protected override void RegisterCssClasses() + { + ClassBuilder.Register(() => Classes?.Root); + } + + protected override void RegisterCssStyles() + { + StyleBuilder.Register(() => Styles?.Root); + } + + protected override async Task OnInitializedAsync() + { + if (IsShownHasBeenSet is false && DefaultIsShown.HasValue) + { + IsShown = DefaultIsShown.Value; + } + + await base.OnInitializedAsync(); + } + + + private async Task Show() + { + _showDelayTokenSource?.Cancel(); + _hideDelayTokenSource?.Cancel(); + + if (ShowDelay > 0) + { + _showDelayTokenSource = new CancellationTokenSource(); + + await Task.Delay(ShowDelay, _showDelayTokenSource.Token); + + _showDelayTokenSource.Dispose(); + _showDelayTokenSource = null; + } + + IsShown = true; + } + + private async Task Hide() + { + _hideDelayTokenSource?.Cancel(); + _showDelayTokenSource?.Cancel(); + + if (HideDelay > 0) + { + _hideDelayTokenSource = new CancellationTokenSource(); + + await Task.Delay(HideDelay, _hideDelayTokenSource.Token); + + _hideDelayTokenSource.Dispose(); + _hideDelayTokenSource = null; + } + + IsShown = false; + } + + private async Task HandlePointerEnter() + { + if (IsShownHasBeenSet && IsShownChanged.HasDelegate is false) return; + if (ShowOnHover is false) return; + + await Show(); + } + + private async Task HandlePointerLeave() + { + if (IsShownHasBeenSet && IsShownChanged.HasDelegate is false) return; + if (ShowOnHover is false) return; + + await Hide(); + } + + private async Task HandleFocusIn() + { + if (IsShownHasBeenSet && IsShownChanged.HasDelegate is false) return; + if (ShowOnFocus is false) return; + + await Show(); + } + + private async Task HandleFocusOut() + { + if (IsShownHasBeenSet && IsShownChanged.HasDelegate is false) return; + if (ShowOnFocus is false) return; + + await Hide(); + } + + private async Task HandlePointerUp() + { + if (IsShownHasBeenSet && IsShownChanged.HasDelegate is false) return; + + if (ShowOnClick) + { + if (IsShown) + { + await Hide(); + } + else + { + await Show(); + } + } + } + + private string GetTooltipClasses() + { + StringBuilder className = new StringBuilder(); + + className.Append(IsShown ? "bit-ttp-vis " : string.Empty); + + className.Append(Position switch + { + BitTooltipPosition.Top => "bit-ttp-top", + BitTooltipPosition.TopLeft => "bit-ttp-tlf", + BitTooltipPosition.TopRight => "bit-ttp-trg", + BitTooltipPosition.RightTop => "bit-ttp-rtp", + BitTooltipPosition.Right => "bit-ttp-rgt", + BitTooltipPosition.RightBottom => "bit-ttp-rbm", + BitTooltipPosition.BottomRight => "bit-ttp-brg", + BitTooltipPosition.Bottom => "bit-ttp-btm", + BitTooltipPosition.BottomLeft => "bit-ttp-blf", + BitTooltipPosition.LeftBottom => "bit-ttp-lbm", + BitTooltipPosition.Left => "bit-ttp-lft", + BitTooltipPosition.LeftTop => "bit-ttp-ltp", + _ => "bit-ttp-top" + }); + + return className.ToString(); + } +} diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltip.scss b/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltip.scss new file mode 100644 index 0000000000..27096a4a80 --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltip.scss @@ -0,0 +1,247 @@ +@import "../../Styles/functions.scss"; + +:root { + --bit-shd-ttp-clr: rgba(0, 0, 0, 0.1); +} + +:root[bit-theme="dark"], +:root[bit-theme="fluent-dark"] { + --bit-shd-ttp-clr: rgba(255, 255, 255, 0.1); +} + +.bit-ttp { + position: relative; + display: inline-flex; + + &.bit-dis { + .bit-ttp-ctn { + color: $color-foreground-disabled; + } + } +} + +.bit-ttp-wrp { + top: 0; + left: 0; + opacity: 0; + width: 100%; + height: 100%; + display: flex; + visibility: hidden; + position: absolute; + pointer-events: none; + transition: all 0.2s linear; + --bit-ttp-arrow-spacing: #{spacing(1.25)}; +} + +.bit-ttp-ctn { + height: auto; + font-weight: 500; + position: absolute; + text-align: center; + width: max-content; + height: max-content; + padding: spacing(1.25); + font-size: spacing(1.5); + z-index: $zindex-callout; + color: $color-foreground-primary; + background-color: $color-background-secondary; +} + +.bit-ttp-vis { + opacity: 1; + visibility: visible; +} + +.bit-ttp-arw { + position: absolute; + width: spacing(1.5); + height: spacing(1.5); + z-index: $zindex-callout; + color: $color-foreground-primary; + background-color: $color-background-secondary; +} + +.bit-ttp-top { + .bit-ttp-ctn { + left: 50%; + transform: translateX(-50%); + box-shadow: $box-shadow-callout; + bottom: calc(100% + var(--bit-ttp-arrow-spacing)); + } + + .bit-ttp-arw { + bottom: 100%; + left: calc(50% - spacing(0.25)); + transform: rotate(45deg) translateX(-50%); + box-shadow: spacing(0.25) spacing(0.25) spacing(0.25) 0 var(--bit-shd-ttp-clr); + } +} + +.bit-ttp-tlf { + .bit-ttp-ctn { + right: calc(100% - var(--bit-ttp-arrow-spacing)); + bottom: calc(100% + var(--bit-ttp-arrow-spacing)); + box-shadow: $box-shadow-callout; + } + + .bit-ttp-arw { + bottom: 100%; + right: calc(100% - var(--bit-ttp-arrow-spacing)); + transform: rotate(45deg) translateX(-50%); + box-shadow: spacing(0.25) spacing(0.25) spacing(0.25) 0 var(--bit-shd-ttp-clr); + } +} + +.bit-ttp-trg { + .bit-ttp-ctn { + left: calc(100% - var(--bit-ttp-arrow-spacing)); + bottom: calc(100% + var(--bit-ttp-arrow-spacing)); + box-shadow: $box-shadow-callout; + } + + .bit-ttp-arw { + left: 100%; + bottom: 100%; + transform: rotate(45deg) translateX(-50%); + box-shadow: spacing(0.25) spacing(0.25) spacing(0.25) 0 var(--bit-shd-ttp-clr); + } +} + +.bit-ttp-rtp { + .bit-ttp-ctn { + left: calc(100% + var(--bit-ttp-arrow-spacing)); + bottom: calc(100% - var(--bit-ttp-arrow-spacing)); + box-shadow: $box-shadow-callout; + } + + .bit-ttp-arw { + left: calc(100% + var(--bit-ttp-arrow-spacing)); + bottom: calc(100% - var(--bit-ttp-arrow-spacing)); + transform: rotate(-45deg) translateY(-50%); + box-shadow: spacing(-0.25) spacing(-0.25) spacing(0.25) 0 var(--bit-shd-ttp-clr); + } +} + +.bit-ttp-rgt { + .bit-ttp-ctn { + bottom: 50%; + transform: translateY(50%); + box-shadow: $box-shadow-callout; + left: calc(100% + var(--bit-ttp-arrow-spacing)); + } + + .bit-ttp-arw { + top: calc(50% - spacing(0.25)); + left: calc(100% + var(--bit-ttp-arrow-spacing)); + transform: rotate(-45deg) translateY(-50%); + box-shadow: spacing(-0.25) spacing(-0.25) spacing(0.25) 0 var(--bit-shd-ttp-clr); + } +} + +.bit-ttp-rbm { + .bit-ttp-ctn { + top: calc(100% - var(--bit-ttp-arrow-spacing)); + left: calc(100% + var(--bit-ttp-arrow-spacing)); + box-shadow: $box-shadow-callout; + } + + .bit-ttp-arw { + top: calc(100% - var(--bit-ttp-arrow-spacing)); + left: calc(100% + var(--bit-ttp-arrow-spacing)); + transform: rotate(-135deg) translateY(-50%); + box-shadow: spacing(0.25) spacing(-0.25) spacing(0.25) 0 var(--bit-shd-ttp-clr); + } +} + +.bit-ttp-brg { + .bit-ttp-ctn { + top: calc(100% + var(--bit-ttp-arrow-spacing)); + left: calc(100% - var(--bit-ttp-arrow-spacing)); + box-shadow: $box-shadow-callout; + } + + .bit-ttp-arw { + top: calc(100% + var(--bit-ttp-arrow-spacing)); + left: calc(100% - var(--bit-ttp-arrow-spacing)); + transform: rotate(135deg) translateX(-50%); + box-shadow: spacing(-0.25) spacing(0.25) spacing(0.25) 0 var(--bit-shd-ttp-clr); + } +} + +.bit-ttp-btm { + .bit-ttp-ctn { + left: 50%; + transform: translateX(-50%); + box-shadow: $box-shadow-callout; + top: calc(100% + var(--bit-ttp-arrow-spacing)); + } + + .bit-ttp-arw { + top: calc(100% + var(--bit-ttp-arrow-spacing)); + left: calc(50% - spacing(0.25)); + transform: rotate(45deg) translateX(-50%); + box-shadow: spacing(-0.25) spacing(-0.25) spacing(0.25) 0 var(--bit-shd-ttp-clr); + } +} + +.bit-ttp-blf { + .bit-ttp-ctn { + top: calc(100% + var(--bit-ttp-arrow-spacing)); + right: calc(100% - var(--bit-ttp-arrow-spacing)); + box-shadow: $box-shadow-callout; + } + + .bit-ttp-arw { + top: calc(100% + var(--bit-ttp-arrow-spacing)); + right: calc(100% - var(--bit-ttp-arrow-spacing)); + transform: rotate(45deg) translateX(-50%); + box-shadow: spacing(-0.25) spacing(-0.25) spacing(0.25) 0 var(--bit-shd-ttp-clr); + } +} + +.bit-ttp-lbm { + .bit-ttp-ctn { + top: calc(100% - var(--bit-ttp-arrow-spacing)); + right: calc(100% + var(--bit-ttp-arrow-spacing)); + box-shadow: $box-shadow-callout; + } + + .bit-ttp-arw { + top: calc(100% - var(--bit-ttp-arrow-spacing)); + right: calc(100% + var(--bit-ttp-arrow-spacing)); + transform: rotate(-135deg) translateX(-50%); + box-shadow: spacing(-0.25) spacing(0.25) spacing(0.25) 0 var(--bit-shd-ttp-clr); + } +} + +.bit-ttp-lft { + .bit-ttp-ctn { + bottom: 50%; + transform: translateY(50%); + box-shadow: $box-shadow-callout; + right: calc(100% + var(--bit-ttp-arrow-spacing)); + } + + .bit-ttp-arw { + top: calc(50% - spacing(0.25)); + right: calc(100% + var(--bit-ttp-arrow-spacing)); + transform: rotate(135deg) translateX(-50%); + box-shadow: spacing(-0.25) spacing(-0.25) spacing(0.25) 0 var(--bit-shd-ttp-clr); + } +} + +.bit-ttp-ltp { + .bit-ttp-ctn { + right: calc(100% + var(--bit-ttp-arrow-spacing)); + bottom: calc(100% - var(--bit-ttp-arrow-spacing)); + box-shadow: $box-shadow-callout; + } + + .bit-ttp-arw { + right: calc(100% + var(--bit-ttp-arrow-spacing)); + bottom: calc(100% - var(--bit-ttp-arrow-spacing)); + transform: rotate(135deg) translateX(-50%); + box-shadow: spacing(-0.25) spacing(-0.25) spacing(0.25) 0 var(--bit-shd-ttp-clr); + } +} diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltipClassStyles.cs b/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltipClassStyles.cs new file mode 100644 index 0000000000..abbfcf349a --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltipClassStyles.cs @@ -0,0 +1,24 @@ +namespace Bit.BlazorUI; + +public class BitTooltipClassStyles +{ + /// + /// Custom CSS classes/styles for the root element of the BitTooltip. + /// + public string? Root { get; set; } + + /// + /// Custom CSS classes/styles for the tooltip wrapper of the BitTooltip. + /// + public string? TooltipWrapper { get; set; } + + /// + /// Custom CSS classes/styles for the tooltip of the BitTooltip. + /// + public string? Tooltip { get; set; } + + /// + /// Custom CSS classes/styles for the arrow of the BitTooltip. + /// + public string? Arrow { get; set; } +} diff --git a/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltipPosition.cs b/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltipPosition.cs new file mode 100644 index 0000000000..8d44c85a34 --- /dev/null +++ b/src/BlazorUI/Bit.BlazorUI/Components/Tooltip/BitTooltipPosition.cs @@ -0,0 +1,64 @@ +namespace Bit.BlazorUI; + +public enum BitTooltipPosition +{ + /// + /// The position of tooltip top of its anchor + /// + Top, + + /// + /// The position of tooltip top left of its anchor + /// + TopLeft, + + /// + /// The position of tooltip top right of its anchor + /// + TopRight, + + /// + /// The position of tooltip right top of its anchor + /// + RightTop, + + /// + /// The position of tooltip right of its anchor + /// + Right, + + /// + /// The position of tooltip right bottom of its anchor + /// + RightBottom, + + /// + /// The position of tooltip bottom right of its anchor + /// + BottomRight, + + /// + /// The position of tooltip bottom of its anchor + /// + Bottom, + + /// + /// The position of tooltip bottom left of its anchor + /// + BottomLeft, + + /// + /// The position of tooltip left bottom of its anchor + /// + LeftBottom, + + /// + /// The position of tooltip left of its anchor + /// + Left, + + /// + /// The position of tooltip left top of its anchor + /// + LeftTop +} diff --git a/src/BlazorUI/Bit.BlazorUI/Styles/components.scss b/src/BlazorUI/Bit.BlazorUI/Styles/components.scss index 8ea8225f3b..0fde2e1ce0 100644 --- a/src/BlazorUI/Bit.BlazorUI/Styles/components.scss +++ b/src/BlazorUI/Bit.BlazorUI/Styles/components.scss @@ -43,10 +43,12 @@ @import "../Components/ProgressIndicator/BitProgressIndicator.scss"; @import "../Components/ScrollablePane/BitScrollablePane.scss"; @import "../Components/Separator/BitSeparator.scss"; +@import "../Components/Shimmer/BitShimmer.scss"; @import "../Components/Slider/BitSlider.scss"; @import "../Components/SnackBar/BitSnackBar.scss"; @import "../Components/Spinner/BitSpinner.scss"; @import "../Components/Stack/BitStack.scss"; @import "../Components/Sticky/BitSticky.scss"; @import "../Components/Swiper/BitSwiper.scss"; +@import "../Components/Tooltip/BitTooltip.scss"; @import "../Components/Typography/BitTypography.scss"; diff --git a/src/BlazorUI/Demo/.editorconfig b/src/BlazorUI/Demo/.editorconfig new file mode 100644 index 0000000000..09b151e99d --- /dev/null +++ b/src/BlazorUI/Demo/.editorconfig @@ -0,0 +1,124 @@ +# To learn more about .editorconfig see https://aka.ms/editorconfigdocs +############################### +# Core EditorConfig Options # +############################### +# All files +[*] +indent_style = space +indent_size = 4 +# Code files +[*.{cs,csx,vb,vbx}] +insert_final_newline = true +charset = utf-8-bom +############################### +# .NET Coding Conventions # +############################### +[*.{cs,vb}] +# Organize usings +dotnet_sort_system_directives_first = true +# this. preferences +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_readonly_field = true:suggestion +# Expression-level preferences +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +############################### +# Naming Conventions # +############################### +# Style Definitions +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +# Use PascalCase for constant fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_accessibilities = * +dotnet_naming_symbols.constant_fields.required_modifiers = const +############################### +# C# Coding Conventions # +############################### +[*.cs] +# var preferences +csharp_style_namespace_declarations = file_scoped:warning +csharp_style_var_for_built_in_types = true:silent +csharp_style_var_when_type_is_apparent = true:silent +csharp_style_var_elsewhere = true:silent +# Expression-bodied members +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +# Pattern matching preferences +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +# Null-checking preferences +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +# Modifier preferences +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion +# Expression-level preferences +csharp_prefer_braces = true:silent +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +############################### +# C# Formatting Rules # +############################### +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true +# Indentation preferences +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left +# Space preferences +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +# Wrapping preferences +csharp_preserve_single_line_statements = true +csharp_preserve_single_line_blocks = true +############################### +# VB Coding Conventions # +############################### +[*.vb] +# Modifier preferences +visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion diff --git a/src/BlazorUI/Demo/.gitignore b/src/BlazorUI/Demo/.gitignore index 575b0b0e6f..13a3d97128 100644 --- a/src/BlazorUI/Demo/.gitignore +++ b/src/BlazorUI/Demo/.gitignore @@ -213,6 +213,9 @@ ModelManifest.xml # VS Code .vscode +# .NET Meteor +.meteor + # Rider .idea @@ -221,13 +224,11 @@ profile.arm.json # Bit.BlazorUI.Demo *.map *Resource.designer.cs +/**/*.css custom.aprof -/Server/Api/Attachments/**/*.* -/Server/Api/BitFileUploaderFiles -/Server/Api/Properties/PublishProfiles/*.* -/Server/Api/Properties/ServiceDependencies/*.* +/Bit.BlazorUI.Demo.Server/Attachments/**/*.* + +/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/scripts/app*.js -/Client/Core/**/*.css -/Client/Core/Scripts/*.js -/Client/Core/wwwroot/scripts/*.js +/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.DemoDb.db* \ No newline at end of file diff --git a/src/BlazorUI/Demo/Server/Api/AppSettings.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/AppSettings.cs similarity index 85% rename from src/BlazorUI/Demo/Server/Api/AppSettings.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/AppSettings.cs index 529aa8eba8..f2d43d44b6 100644 --- a/src/BlazorUI/Demo/Server/Api/AppSettings.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/AppSettings.cs @@ -1,4 +1,4 @@ -namespace Bit.BlazorUI.Demo.Server.Api; +namespace Bit.BlazorUI.Demo.Server; public class AppSettings { diff --git a/src/BlazorUI/Demo/Server/Api/Bit.BlazorUI.Demo.Server.Api.csproj b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj similarity index 56% rename from src/BlazorUI/Demo/Server/Api/Bit.BlazorUI.Demo.Server.Api.csproj rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj index 290a3fd146..0ffa3aae16 100644 --- a/src/BlazorUI/Demo/Server/Api/Bit.BlazorUI.Demo.Server.Api.csproj +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Bit.BlazorUI.Demo.Server.csproj @@ -5,24 +5,14 @@ - - - - - - - - - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - @@ -30,7 +20,8 @@ - + + @@ -40,7 +31,22 @@ - + + + + + + + + + True + True + $([System.String]::Copy('%(Filename)').Replace('.Designer','')).resx + + + PublicResXFileCodeGenerator + %(Filename).Designer.cs + diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor new file mode 100644 index 0000000000..b488255dc1 --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor @@ -0,0 +1,84 @@ +@using Bit.BlazorUI.Demo.Client.Web.Components + +@{ + var noPrerender = HttpContext.Request.Query["no-prerender"].Count > 0; + var renderMode = noPrerender ? AppRenderMode.NoPrerenderBlazorWebAssembly : AppRenderMode.Current; +} + + + + + + + + + + + + + + @if (AppRenderMode.PwaEnabled) + { + + } + + + + + + + + + + + + + + + + + + + + + + + @if (HttpContext.Request.IsCrawlerClient() is false) + { + @if (AppRenderMode.PwaEnabled) + { + + + + + } + else + { + + } + + + + + } + + + + diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor.cs new file mode 100644 index 0000000000..0a26c3519c --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/App.razor.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Components; + +namespace Bit.BlazorUI.Demo.Server.Components; + +[StreamRendering(enabled: true)] +public partial class App +{ + [CascadingParameter] HttpContext HttpContext { get; set; } = default!; +} diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/Link.razor b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/Link.razor new file mode 100644 index 0000000000..81cd008c0a --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/Link.razor @@ -0,0 +1,18 @@ +@using Microsoft.AspNetCore.Mvc.ViewFeatures +@inject IFileVersionProvider _fileVersionProvider +@inject IHttpContextAccessor _httpContextAccessor; + +@code { + [Parameter] public bool AppendVersion { get; set; } = true; + [Parameter] public required string Href { get; set; } = ""; + [Parameter(CaptureUnmatchedValues = true)] public Dictionary AdditionalAttributes { get; set; } = default!; + + private string href = ""; + + protected override void OnInitialized() + { + href = AppendVersion ? _fileVersionProvider.AddFileVersionToPath(_httpContextAccessor.HttpContext!.Request.PathBase, Href) : Href; + } +} + + diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/Script.razor b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/Script.razor new file mode 100644 index 0000000000..9394c9f44c --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/Script.razor @@ -0,0 +1,28 @@ +@using Microsoft.AspNetCore.Mvc.ViewFeatures +@inject IFileVersionProvider _fileVersionProvider +@inject IHttpContextAccessor _httpContextAccessor; + +@code { + [Parameter] public bool AppendVersion { get; set; } = true; + [Parameter] public string? Src { get; set; } + [Parameter] public RenderFragment? ChildContent { get; set; } + [Parameter(CaptureUnmatchedValues = true)] public Dictionary AdditionalAttributes { get; set; } = default!; + + private string? src; + + protected override void OnInitialized() + { + src = (Src is not null && AppendVersion) ? _fileVersionProvider.AddFileVersionToPath(_httpContextAccessor.HttpContext!.Request.PathBase, Src) : Src; + } +} + +@if (src is not null) +{ + +} +else +{ + +} \ No newline at end of file diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/_Imports.razor b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/_Imports.razor new file mode 100644 index 0000000000..d70389d38a --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Components/_Imports.razor @@ -0,0 +1,7 @@ +@using System +@using Microsoft.Extensions.Localization +@using Microsoft.AspNetCore.Components.Web +@using Bit.BlazorUI.Demo.Client.Core +@using Bit.BlazorUI.Demo.Client.Core.Components +@using Bit.BlazorUI.Demo.Client.Core.Services +@using Bit.BlazorUI \ No newline at end of file diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Controllers/AppControllerBase.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Controllers/AppControllerBase.cs new file mode 100644 index 0000000000..82942ec4c1 --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Controllers/AppControllerBase.cs @@ -0,0 +1,6 @@ +namespace Bit.BlazorUI.Demo.Server.Controllers; + +public partial class AppControllerBase : ControllerBase +{ + [AutoInject] protected AppSettings AppSettings = default!; +} diff --git a/src/BlazorUI/Demo/Server/Api/Controllers/ComponentDetailsController.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Controllers/ComponentDetailsController.cs similarity index 98% rename from src/BlazorUI/Demo/Server/Api/Controllers/ComponentDetailsController.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Controllers/ComponentDetailsController.cs index 98278b49db..c2cb8267f1 100644 --- a/src/BlazorUI/Demo/Server/Api/Controllers/ComponentDetailsController.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Controllers/ComponentDetailsController.cs @@ -1,8 +1,7 @@ using System.Reflection; using System.Xml.Linq; -using Bit.BlazorUI.Demo.Server.Api.Controllers; -namespace Bit.BlazorUI.Demo.Api.Controllers; +namespace Bit.BlazorUI.Demo.Server.Controllers; [ApiController] [Route("api/[controller]/[action]")] diff --git a/src/BlazorUI/Demo/Server/Api/Controllers/FileUploadController.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Controllers/FileUploadController.cs similarity index 95% rename from src/BlazorUI/Demo/Server/Api/Controllers/FileUploadController.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Controllers/FileUploadController.cs index 9ad9947b64..f35c18730a 100644 --- a/src/BlazorUI/Demo/Server/Api/Controllers/FileUploadController.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Controllers/FileUploadController.cs @@ -1,7 +1,4 @@ -using Bit.BlazorUI.Demo.Server.Api; -using Bit.BlazorUI.Demo.Server.Api.Controllers; - -namespace Bit.BlazorUI.Demo.Api.Controllers; +namespace Bit.BlazorUI.Demo.Server.Controllers; [ApiController] [Route("api/[controller]/[action]")] diff --git a/src/BlazorUI/Demo/Server/Api/Controllers/ProductsController.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Controllers/ProductsController.cs similarity index 96% rename from src/BlazorUI/Demo/Server/Api/Controllers/ProductsController.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Controllers/ProductsController.cs index 5c568bd738..2b64211c11 100644 --- a/src/BlazorUI/Demo/Server/Api/Controllers/ProductsController.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Controllers/ProductsController.cs @@ -1,6 +1,4 @@ -using Bit.BlazorUI.Demo.Server.Api.Controllers; - -namespace Bit.BlazorUI.Demo.Api.Controllers; +namespace Bit.BlazorUI.Demo.Server.Controllers; [ApiController] [Route("api/[controller]/[action]")] diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Extensions/HttpRequestExtensions.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Extensions/HttpRequestExtensions.cs new file mode 100644 index 0000000000..6b0aa99f04 --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Extensions/HttpRequestExtensions.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; + +namespace Microsoft.AspNetCore.Http; + +public static class HttpRequestExtensions +{ + /// + /// https://blog.elmah.io/how-to-get-base-url-in-asp-net-core/ + /// + public static Uri GetBaseUrl(this HttpRequest req) + { + var uriBuilder = new UriBuilder(req.Scheme, req.Host.Host, req.Host.Port ?? -1); + if (uriBuilder.Uri.IsDefaultPort) + { + uriBuilder.Port = -1; + } + + return uriBuilder.Uri; + } + + public static bool IsCrawlerClient(this HttpRequest request) + { + if (request.Headers.TryGetValue(HeaderNames.UserAgent, out StringValues userAgentHeaderValue) is false) + return false; + + string? userAgent = userAgentHeaderValue.FirstOrDefault(); + + if (userAgent is null) + return false; + + if (userAgent.Contains("google", StringComparison.InvariantCultureIgnoreCase)) return true; + + if (userAgent.Contains("bing", StringComparison.InvariantCultureIgnoreCase)) return true; + + if (userAgent.Contains("lighthouse", StringComparison.InvariantCultureIgnoreCase)) return true; + + return false; + } +} diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Extensions/IServiceCollectionExtensions.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Extensions/IServiceCollectionExtensions.cs new file mode 100644 index 0000000000..b3d0d01913 --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Extensions/IServiceCollectionExtensions.cs @@ -0,0 +1,67 @@ +using Bit.BlazorUI.Demo.Client.Core.Services.HttpMessageHandlers; +using Bit.BlazorUI.Demo.Server; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class IServiceCollectionExtensions +{ + public static void AddBlazor(this IServiceCollection services, IConfiguration configuration) + { + services.AddTransient(sp => + { + Uri.TryCreate(configuration.GetApiServerAddress(), UriKind.RelativeOrAbsolute, out var apiServerAddress); + + if (apiServerAddress!.IsAbsoluteUri is false) + { + apiServerAddress = new Uri(sp.GetRequiredService().HttpContext!.Request.GetBaseUrl(), apiServerAddress); + } + + return new HttpClient(sp.GetRequiredService()) + { + BaseAddress = apiServerAddress + }; + }); + + services.AddRazorComponents() + .AddInteractiveServerComponents() + .AddInteractiveWebAssemblyComponents(); + + services.AddMvc(); + + services.AddClientWebServices(); + } + + public static void AddSwaggerGen(this IServiceCollection services) + { + services.AddSwaggerGen(options => + { + options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "Bit.BlazorUI.Demo.Server.xml")); + options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "Bit.BlazorUI.Demo.Shared.xml")); + + options.OperationFilter(); + }); + } + + public static IServiceCollection AddHealthChecks(this IServiceCollection services, IWebHostEnvironment env, IConfiguration configuration) + { + var appSettings = configuration.GetSection(nameof(AppSettings)).Get()!; + + var healthCheckSettings = appSettings.HealthCheckSettings; + + if (healthCheckSettings.EnableHealthChecks is false) + return services; + + services.AddHealthChecksUI(setupSettings: setup => + { + setup.AddHealthCheckEndpoint("BPHealthChecks", env.IsDevelopment() ? "https://localhost:5031/healthz" : "/healthz"); + }).AddInMemoryStorage(); + + var healthChecksBuilder = services.AddHealthChecks() + .AddProcessAllocatedMemoryHealthCheck(maximumMegabytesAllocated: 6 * 1024) + .AddDiskStorageHealthCheck(opt => + opt.AddDrive(Path.GetPathRoot(Directory.GetCurrentDirectory())!, minimumFreeMegabytes: 5 * 1024)); + + return services; + } +} diff --git a/src/BlazorUI/Demo/Server/Api/Extensions/ODataOperationFilter.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Extensions/ODataOperationFilter.cs similarity index 83% rename from src/BlazorUI/Demo/Server/Api/Extensions/ODataOperationFilter.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Extensions/ODataOperationFilter.cs index 6057cb4a80..3d2ba9b1a6 100644 --- a/src/BlazorUI/Demo/Server/Api/Extensions/ODataOperationFilter.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Extensions/ODataOperationFilter.cs @@ -12,13 +12,16 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) { if (operation.Parameters == null) operation.Parameters = new List(); - var descriptor = (ControllerActionDescriptor)context.ApiDescription.ActionDescriptor; + var descriptor = context.ApiDescription.ActionDescriptor as ControllerActionDescriptor; - var odataQueryOptionsParameter = descriptor.Parameters.SingleOrDefault(p => typeof(ODataQueryOptions).IsAssignableFrom(p.ParameterType)); + if (descriptor is null) + return; + + var odataQueryOptionsParameter = descriptor!.Parameters.SingleOrDefault(p => typeof(ODataQueryOptions).IsAssignableFrom(p.ParameterType)); if (descriptor != null && descriptor.FilterDescriptors.Any(filter => filter.Filter is EnableQueryAttribute) || odataQueryOptionsParameter is not null) { - operation.Parameters.Add(new OpenApiParameter() + operation.Parameters.Add(new() { Name = "$select", In = ParameterLocation.Query, @@ -30,7 +33,7 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) Required = false }); - operation.Parameters.Add(new OpenApiParameter() + operation.Parameters.Add(new() { Name = "$expand", In = ParameterLocation.Query, @@ -42,7 +45,7 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) Required = false }); - operation.Parameters.Add(new OpenApiParameter() + operation.Parameters.Add(new() { Name = "$filter", In = ParameterLocation.Query, @@ -54,7 +57,7 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) Required = false }); - operation.Parameters.Add(new OpenApiParameter() + operation.Parameters.Add(new() { Name = "$search", In = ParameterLocation.Query, @@ -66,7 +69,7 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) Required = false }); - operation.Parameters.Add(new OpenApiParameter() + operation.Parameters.Add(new() { Name = "$top", In = ParameterLocation.Query, @@ -78,7 +81,7 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) Required = false }); - operation.Parameters.Add(new OpenApiParameter() + operation.Parameters.Add(new() { Name = "$skip", In = ParameterLocation.Query, @@ -90,7 +93,7 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) Required = false }); - operation.Parameters.Add(new OpenApiParameter() + operation.Parameters.Add(new() { Name = "$orderby", In = ParameterLocation.Query, diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Mappers/Readme.md b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Mappers/Readme.md new file mode 100644 index 0000000000..fad9970be8 --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Mappers/Readme.md @@ -0,0 +1,17 @@ +When you have an IQueryable of an Entity or Model classes from EntityFrameworkCore, +you ultimately need to convert it into an IQueryable of DTO classes and return it to the client. +The client can also implement pagination during the API call by sending values for $top, $skip and sort by $orderby in request query string. +Ultimately, the query is executed by aspnetcore and the data gets streamed from the database to the client, which is the most optimal case. +For this, you need to write a `Project` for each Entity you intend to return a query of DTO class from. + +You also write a `Map` for when a DTO is sent to the server for create or update api, +so you can convert it to an Entity and save it in the database using ef core. +You also need a Map method to convert DTO to Entity and vice versa. + +You also need a `Patch` method for the update scenario, to perform update operation, first get the Entity from the database with its Id, +then patch the latest changes from the DTO sent by the client, and finally save it. + +These methods (`Project`, `Map` and `Patch`) are gets called in controllers. + +For more information and to learn about customizing the mapping process, visit the website below: +https://mapperly.riok.app/docs/intro/ \ No newline at end of file diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Program.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Program.cs new file mode 100644 index 0000000000..8cb1b1b030 --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Program.cs @@ -0,0 +1,24 @@ +var builder = WebApplication.CreateBuilder(args); + +builder.Configuration.AddClientConfigurations(); + +if (BuildConfiguration.IsDebug()) +{ + // The following line (using the * in the URL), allows the emulators and mobile devices to access the app using the host IP address. + if (OperatingSystem.IsWindows()) + { + builder.WebHost.UseUrls("https://localhost:5031", "http://localhost:5030", "https://*:5031", "http://*:5030"); + } + else + { + builder.WebHost.UseUrls("https://localhost:5031", "http://localhost:5030"); + } +} + +Bit.BlazorUI.Demo.Server.Startup.Services.Add(builder.Services, builder.Environment, builder.Configuration); + +var app = builder.Build(); + +Bit.BlazorUI.Demo.Server.Startup.Middlewares.Use(app, builder.Environment, builder.Configuration); + +app.Run(); diff --git a/src/BlazorUI/Demo/Server/Api/Properties/launchSettings.json b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Properties/launchSettings.json similarity index 68% rename from src/BlazorUI/Demo/Server/Api/Properties/launchSettings.json rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Properties/launchSettings.json index ed1ffcdab4..91d5372c34 100644 --- a/src/BlazorUI/Demo/Server/Api/Properties/launchSettings.json +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Properties/launchSettings.json @@ -1,22 +1,23 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { - "Bit.BlazorUI.Demo.Server.Api": { + "Bit.BlazorUI.Demo.Server-Swagger": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "https://localhost:5001;http://localhost:5000", + "applicationUrl": "http://localhost:5030;https://localhost:5031", "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, // This configuration allows debugging the Blazor Web Assembly - "Bit.BlazorUI.Demo.Server.Api-BlazorWebAssembly": { + "Bit.BlazorUI.Demo.Server-BlazorWebAssembly": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", - "applicationUrl": "https://localhost:5001;http://localhost:5000", + "applicationUrl": "http://localhost:5030;https://localhost:5031", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Services/ServerExceptionHandler.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Services/ServerExceptionHandler.cs new file mode 100644 index 0000000000..e07053cd64 --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Services/ServerExceptionHandler.cs @@ -0,0 +1,51 @@ +using System.Net; +using System.Reflection; +using Microsoft.AspNetCore.Diagnostics; +using Microsoft.Net.Http.Headers; + +namespace Bit.BlazorUI.Demo.Server.Services; + +public partial class ServerExceptionHandler : IExceptionHandler +{ + [AutoInject] private IWebHostEnvironment webHostEnvironment = default!; + + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e, CancellationToken cancellationToken) + { + // Using the Request-Id header, one can find the log for server-related exceptions + httpContext.Response.Headers.Append(HeaderNames.RequestId, httpContext.TraceIdentifier); + + var exception = UnWrapException(e); + var knownException = exception as KnownException; + + // The details of all of the exceptions are returned only in dev mode. in any other modes like production, only the details of the known exceptions are returned. + var key = knownException?.Key ?? nameof(UnknownException); + var message = knownException?.Message ?? (webHostEnvironment.IsDevelopment() ? exception.Message : nameof(UnknownException)); + + var statusCode = (int)(exception is RestException restExp ? restExp.StatusCode : HttpStatusCode.InternalServerError); + + var restExceptionPayload = new RestErrorInfo + { + Key = key, + Message = message, + ExceptionType = knownException?.GetType().FullName ?? typeof(UnknownException).FullName + }; + + if (exception is ResourceValidationException validationException) + { + restExceptionPayload.Payload = validationException.Payload; + } + + httpContext.Response.StatusCode = statusCode; + + await httpContext.Response.WriteAsJsonAsync(restExceptionPayload, AppJsonContext.Default.RestErrorInfo, cancellationToken: cancellationToken); + + return true; + } + + private Exception UnWrapException(Exception exp) + { + return exp is TargetInvocationException && exp.InnerException is not null + ? exp.InnerException + : exp; + } +} diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Startup/Middlewares.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Startup/Middlewares.cs new file mode 100644 index 0000000000..2055602f16 --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Startup/Middlewares.cs @@ -0,0 +1,135 @@ +using System.Net; +using System.Reflection; +using System.Runtime.Loader; +using Bit.BlazorUI.Demo.Server.Components; +using HealthChecks.UI.Client; +using Microsoft.AspNetCore.Components.Endpoints; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.AspNetCore.Http.Extensions; + +namespace Bit.BlazorUI.Demo.Server.Startup; + +public class Middlewares +{ + public static void Use(WebApplication app, IHostEnvironment env, IConfiguration configuration) + { + app.UseForwardedHeaders(); + + if (env.IsDevelopment()) + { + app.UseWebAssemblyDebugging(); + } + else + { + app.UseHttpsRedirection(); + app.UseResponseCompression(); + } + + Configure_401_403_404_Pages(app); + + app.UseStaticFiles(new StaticFileOptions + { + OnPrepareResponse = ctx => + { + // https://bitplatform.dev/templates/cache-mechanism + ctx.Context.Response.GetTypedHeaders().CacheControl = new() + { + MaxAge = TimeSpan.FromDays(7), + Public = true + }; + } + }); + + app.UseCors(options => options.WithOrigins("https://0.0.0.0" /*BlazorHybrid*/, "app://0.0.0.0" /*BlazorHybrid*/) + .AllowAnyHeader().AllowAnyMethod()); + + app.UseResponseCaching(); + app.UseAntiforgery(); + + app.UseExceptionHandler("/", createScopeForErrors: true); + + app.UseSwagger(); + + app.UseSwaggerUI(); + + app.MapControllers(); + + var appSettings = configuration.GetSection(nameof(AppSettings)).Get()!; + + var healthCheckSettings = appSettings.HealthCheckSettings; + + if (healthCheckSettings.EnableHealthChecks) + { + app.MapHealthChecks("/healthz", new HealthCheckOptions + { + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + + app.MapHealthChecksUI(options => + { + options.UseRelativeApiPath = + options.UseRelativeResourcesPath = + options.UseRelativeWebhookPath = false; + }); + } + + // Handle the rest of requests with blazor + app.MapRazorComponents() + .AddInteractiveServerRenderMode() + .AddInteractiveWebAssemblyRenderMode() + .AddAdditionalAssemblies(AssemblyLoadContext.Default.Assemblies.Where(asm => asm.GetName().Name?.Contains("Bit.BlazorUI.Demo") is true).Except([Assembly.GetExecutingAssembly()]).ToArray()); + } + + /// + /// Prior to the introduction of .NET 8, the Blazor router effectively managed NotFound and NotAuthorized components during pre-rendering. + /// However, the current behavior has changed, and it now exclusively returns 401, 403, and 404 status codes with an empty body response! + /// To address this, we've implemented the UseStatusCodePages middleware to handle responses featuring 401, 403, and 404 status codes that lack a body. + /// This middleware facilitates redirection to the appropriate not-found and not-authorized pages. Consequently, the status code for these responses becomes 302 (Found). + /// To mitigate the challenges posed by this situation, our only recourse is to repurpose the 401, 403, and 404 status codes for + /// not-found and not-authorized responses, at the very least. + /// + private static void Configure_401_403_404_Pages(WebApplication app) + { + app.Use(async (context, next) => + { + if (context.Request.Path.HasValue) + { + if (context.Request.Path.Value.Contains("not-found", StringComparison.InvariantCultureIgnoreCase)) + { + context.Response.StatusCode = (int)HttpStatusCode.NotFound; + } + if (context.Request.Path.Value.Contains("not-authorized", StringComparison.InvariantCultureIgnoreCase)) + { + context.Response.StatusCode = context.Request.Query["isForbidden"].FirstOrDefault() is "true" ? (int)HttpStatusCode.Forbidden : (int)HttpStatusCode.Unauthorized; + } + } + + await next.Invoke(context); + }); + + app.UseStatusCodePages(options: new() + { + HandleAsync = async (statusCodeContext) => + { + var httpContext = statusCodeContext.HttpContext; + + if (httpContext.Response.StatusCode is 401 or 403 && + httpContext.GetEndpoint()?.Metadata.OfType().Any() is true /* The generation of a 401 or 403 status code is attributed to Blazor. */) + { + bool is403 = httpContext.Response.StatusCode is 403; + + httpContext.Response.Redirect($"/not-authorized?redirect-url={httpContext.Request.GetEncodedPathAndQuery()}&isForbidden={(is403 ? "true" : "false")}"); + } + else if (httpContext.Response.StatusCode is 404 && + httpContext.GetEndpoint() is null /* Please be aware that certain endpoints, particularly those associated with web API actions, may intentionally return a 404 error. */) + { + httpContext.Response.Redirect($"/not-found?url={httpContext.Request.GetEncodedPathAndQuery()}"); + } + else + { + await statusCodeContext.Next.Invoke(statusCodeContext.HttpContext); + } + } + }); + } +} diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Startup/Services.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Startup/Services.cs new file mode 100644 index 0000000000..9da41ac2bf --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/Startup/Services.cs @@ -0,0 +1,70 @@ +using System.IO.Compression; +using System.Net; +using System.Net.Mail; +using Bit.BlazorUI.Demo.Server.Services; +using Microsoft.AspNetCore.Components.Web; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.OData; +using Microsoft.AspNetCore.ResponseCompression; + +namespace Bit.BlazorUI.Demo.Server.Startup; + +public static class Services +{ + public static void Add(IServiceCollection services, IWebHostEnvironment env, IConfiguration configuration) + { + // Services being registered here can get injected into controllers and services in Server project. + + var appSettings = configuration.GetSection(nameof(AppSettings)).Get()!; + + services.AddExceptionHandler(); + + services.AddBlazor(configuration); + + services.AddClientSharedServices(); + + + services.AddCors(); + + services + .AddControllers() + .AddOData(options => options.EnableQueryFeatures()) + .ConfigureApiBehaviorOptions(options => + { + options.InvalidModelStateResponseFactory = context => + { + throw new ResourceValidationException(context.ModelState.Select(ms => (ms.Key, ms.Value!.Errors.Select(e => new LocalizedString(e.ErrorMessage, e.ErrorMessage)).ToArray())).ToArray()); + }; + }); + + services.Configure(options => + { + options.ForwardedHeaders = ForwardedHeaders.All; + options.ForwardedHostHeaderName = "X-Host"; + }); + + services.AddResponseCaching(); + + services.AddHttpContextAccessor(); + + services.AddResponseCompression(opts => + { + opts.EnableForHttps = true; + opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(["application/octet-stream"]).ToArray(); + opts.Providers.Add(); + opts.Providers.Add(); + }) + .Configure(opt => opt.Level = CompressionLevel.Fastest) + .Configure(opt => opt.Level = CompressionLevel.Fastest); + + services.Configure(configuration.GetSection(nameof(AppSettings))); + + services.AddTransient(sp => sp.GetRequiredService>().Value); + + services.AddEndpointsApiExplorer(); + + services.AddSwaggerGen(); + + services.AddHealthChecks(env, configuration); + } +} diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/appsettings.Development.json b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/appsettings.Development.json new file mode 100644 index 0000000000..f3f302cced --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/appsettings.Development.json @@ -0,0 +1,5 @@ +{ + "AppSettings": { + + } +} \ No newline at end of file diff --git a/src/BlazorUI/Demo/Server/Api/appsettings.json b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/appsettings.json similarity index 100% rename from src/BlazorUI/Demo/Server/Api/appsettings.json rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/appsettings.json diff --git a/src/BlazorUI/Demo/Server/Api/wwwroot/images/icon.png b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/wwwroot/images/icon.png similarity index 100% rename from src/BlazorUI/Demo/Server/Api/wwwroot/images/icon.png rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Server/wwwroot/images/icon.png diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Attributes/AutoInjectAttribute.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Attributes/AutoInjectAttribute.cs new file mode 100644 index 0000000000..65d16737c5 --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Attributes/AutoInjectAttribute.cs @@ -0,0 +1,10 @@ +namespace Microsoft.Extensions.DependencyInjection; + +/// +/// By applying this attribute to either fields or properties, the bit source generator will automatically +/// generate the remaining code necessary to inject that field or property using dependency injection. +/// +[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, Inherited = false, AllowMultiple = false)] +public sealed class AutoInjectAttribute : Attribute +{ +} diff --git a/src/BlazorUI/Demo/Shared/Bit.BlazorUI.Demo.Shared.csproj b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Bit.BlazorUI.Demo.Shared.csproj similarity index 85% rename from src/BlazorUI/Demo/Shared/Bit.BlazorUI.Demo.Shared.csproj rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Bit.BlazorUI.Demo.Shared.csproj index cc63fe492d..e9a165cf6d 100644 --- a/src/BlazorUI/Demo/Shared/Bit.BlazorUI.Demo.Shared.csproj +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Bit.BlazorUI.Demo.Shared.csproj @@ -5,11 +5,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -17,11 +17,13 @@ + + compile; build; native; contentfiles; analyzers; buildtransitive + - diff --git a/src/BlazorUI/Demo/Shared/Dtos/AppJsonContext.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/AppJsonContext.cs similarity index 99% rename from src/BlazorUI/Demo/Shared/Dtos/AppJsonContext.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/AppJsonContext.cs index 832beafabd..f2d4a0b5d4 100644 --- a/src/BlazorUI/Demo/Shared/Dtos/AppJsonContext.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/AppJsonContext.cs @@ -16,5 +16,4 @@ namespace Bit.BlazorUI.Demo.Shared.Dtos; [JsonSerializable(typeof(RestErrorInfo))] public partial class AppJsonContext : JsonSerializerContext { - } diff --git a/src/BlazorUI/Demo/Shared/Dtos/CategoryOrProductDto.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/CategoryOrProductDto.cs similarity index 100% rename from src/BlazorUI/Demo/Shared/Dtos/CategoryOrProductDto.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/CategoryOrProductDto.cs diff --git a/src/BlazorUI/Demo/Shared/Dtos/ComponentMethodDetailsDto.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/ComponentMethodDetailsDto.cs similarity index 100% rename from src/BlazorUI/Demo/Shared/Dtos/ComponentMethodDetailsDto.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/ComponentMethodDetailsDto.cs diff --git a/src/BlazorUI/Demo/Shared/Dtos/ComponentPropertyDetailsDto.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/ComponentPropertyDetailsDto.cs similarity index 100% rename from src/BlazorUI/Demo/Shared/Dtos/ComponentPropertyDetailsDto.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/ComponentPropertyDetailsDto.cs diff --git a/src/BlazorUI/Demo/Shared/Dtos/DataGridDemo/FoodRecall.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/DataGridDemo/FoodRecall.cs similarity index 100% rename from src/BlazorUI/Demo/Shared/Dtos/DataGridDemo/FoodRecall.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/DataGridDemo/FoodRecall.cs diff --git a/src/BlazorUI/Demo/Shared/Dtos/DataGridDemo/FoodRecallQueryResult.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/DataGridDemo/FoodRecallQueryResult.cs similarity index 100% rename from src/BlazorUI/Demo/Shared/Dtos/DataGridDemo/FoodRecallQueryResult.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/DataGridDemo/FoodRecallQueryResult.cs diff --git a/src/BlazorUI/Demo/Shared/Dtos/DataGridDemo/Meta.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/DataGridDemo/Meta.cs similarity index 100% rename from src/BlazorUI/Demo/Shared/Dtos/DataGridDemo/Meta.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/DataGridDemo/Meta.cs diff --git a/src/BlazorUI/Demo/Shared/Dtos/DataGridDemo/Openfda.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/DataGridDemo/Openfda.cs similarity index 100% rename from src/BlazorUI/Demo/Shared/Dtos/DataGridDemo/Openfda.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/DataGridDemo/Openfda.cs diff --git a/src/BlazorUI/Demo/Shared/Dtos/DataGridDemo/Results.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/DataGridDemo/Results.cs similarity index 100% rename from src/BlazorUI/Demo/Shared/Dtos/DataGridDemo/Results.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/DataGridDemo/Results.cs diff --git a/src/BlazorUI/Demo/Shared/Dtos/PagedResult.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/PagedResultDto.cs similarity index 100% rename from src/BlazorUI/Demo/Shared/Dtos/PagedResult.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/PagedResultDto.cs diff --git a/src/BlazorUI/Demo/Shared/Dtos/ProductDto.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/ProductDto.cs similarity index 100% rename from src/BlazorUI/Demo/Shared/Dtos/ProductDto.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Dtos/ProductDto.cs diff --git a/src/BlazorUI/Demo/Shared/Exceptions/BadRequestException.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/BadRequestException.cs similarity index 92% rename from src/BlazorUI/Demo/Shared/Exceptions/BadRequestException.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/BadRequestException.cs index 8e068ed5be..ffcbed06c8 100644 --- a/src/BlazorUI/Demo/Shared/Exceptions/BadRequestException.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/BadRequestException.cs @@ -5,7 +5,7 @@ namespace Bit.BlazorUI.Demo.Shared.Exceptions; public class BadRequestException : RestException { public BadRequestException() - : base(nameof(AppStrings.BadRequestException)) + : base(nameof(BadRequestException)) { } diff --git a/src/BlazorUI/Demo/Shared/Exceptions/ConflictException.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ConflictException.cs similarity index 92% rename from src/BlazorUI/Demo/Shared/Exceptions/ConflictException.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ConflictException.cs index 3db7957e1e..2f4fc2c7ee 100644 --- a/src/BlazorUI/Demo/Shared/Exceptions/ConflictException.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ConflictException.cs @@ -5,7 +5,7 @@ namespace Bit.BlazorUI.Demo.Shared.Exceptions; public class ConflictException : RestException { public ConflictException() - : this(nameof(AppStrings.ConflicException)) + : this(nameof(ConflictException)) { } diff --git a/src/BlazorUI/Demo/Shared/Exceptions/DomainLogicException.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/DomainLogicException.cs similarity index 99% rename from src/BlazorUI/Demo/Shared/Exceptions/DomainLogicException.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/DomainLogicException.cs index cf825e08f1..a1ef1e6699 100644 --- a/src/BlazorUI/Demo/Shared/Exceptions/DomainLogicException.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/DomainLogicException.cs @@ -21,5 +21,4 @@ public DomainLogicException(LocalizedString message, Exception? innerException) : base(message, innerException) { } - } diff --git a/src/BlazorUI/Demo/Shared/Exceptions/ErrorResourcePayload.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ErrorResourcePayload.cs similarity index 84% rename from src/BlazorUI/Demo/Shared/Exceptions/ErrorResourcePayload.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ErrorResourcePayload.cs index 5107374bfb..4f8863778a 100644 --- a/src/BlazorUI/Demo/Shared/Exceptions/ErrorResourcePayload.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ErrorResourcePayload.cs @@ -4,14 +4,14 @@ public class ErrorResourcePayload { public string? ResourceTypeName { get; set; } = "*"; - public List Details { get; set; } = new(); + public List Details { get; set; } = []; } public class PropertyErrorResourceCollection { public string? Name { get; set; } = "*"; - public List Errors { get; set; } = new(); + public List Errors { get; set; } = []; } public class ErrorResource diff --git a/src/BlazorUI/Demo/Shared/Exceptions/ForbiddenException.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ForbiddenException.cs similarity index 92% rename from src/BlazorUI/Demo/Shared/Exceptions/ForbiddenException.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ForbiddenException.cs index ef7070a487..1ebaff30ea 100644 --- a/src/BlazorUI/Demo/Shared/Exceptions/ForbiddenException.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ForbiddenException.cs @@ -5,7 +5,7 @@ namespace Bit.BlazorUI.Demo.Shared.Exceptions; public class ForbiddenException : RestException { public ForbiddenException() - : base(nameof(AppStrings.ForbiddenException)) + : base(nameof(ForbiddenException)) { } diff --git a/src/BlazorUI/Demo/Shared/Exceptions/KnownException.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/KnownException.cs similarity index 100% rename from src/BlazorUI/Demo/Shared/Exceptions/KnownException.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/KnownException.cs diff --git a/src/BlazorUI/Demo/Shared/Exceptions/ResourceNotFoundException.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ResourceNotFoundException.cs similarity index 92% rename from src/BlazorUI/Demo/Shared/Exceptions/ResourceNotFoundException.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ResourceNotFoundException.cs index e2f2b39f89..5341df8e55 100644 --- a/src/BlazorUI/Demo/Shared/Exceptions/ResourceNotFoundException.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ResourceNotFoundException.cs @@ -5,7 +5,7 @@ namespace Bit.BlazorUI.Demo.Shared.Exceptions; public class ResourceNotFoundException : RestException { public ResourceNotFoundException() - : base(nameof(AppStrings.ResourceNotFoundException)) + : base(nameof(ResourceNotFoundException)) { } diff --git a/src/BlazorUI/Demo/Shared/Exceptions/ResourceValidationException.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ResourceValidationException.cs similarity index 92% rename from src/BlazorUI/Demo/Shared/Exceptions/ResourceValidationException.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ResourceValidationException.cs index 03cf72ac5b..07718e3cb5 100644 --- a/src/BlazorUI/Demo/Shared/Exceptions/ResourceValidationException.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ResourceValidationException.cs @@ -5,7 +5,7 @@ namespace Bit.BlazorUI.Demo.Shared.Exceptions; public class ResourceValidationException : RestException { public ResourceValidationException(params LocalizedString[] errorMessages) - : this(new[] { ("*", errorMessages) }) + : this([("*", errorMessages)]) { } @@ -41,7 +41,7 @@ public ResourceValidationException(string resourceTypeName, (string propName, Lo } public ResourceValidationException(ErrorResourcePayload payload) - : this(message: nameof(AppStrings.ResourceValidationException), payload) + : this(message: nameof(ResourceValidationException), payload) { } diff --git a/src/BlazorUI/Demo/Shared/Exceptions/RestErrorInfo.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/RestErrorInfo.cs similarity index 76% rename from src/BlazorUI/Demo/Shared/Exceptions/RestErrorInfo.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/RestErrorInfo.cs index 6c7f02e59a..23d161328a 100644 --- a/src/BlazorUI/Demo/Shared/Exceptions/RestErrorInfo.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/RestErrorInfo.cs @@ -8,5 +8,5 @@ public class RestErrorInfo public string? Message { get; set; } - public ErrorResourcePayload Payload { get; set; } = new(); + public ErrorResourcePayload? Payload { get; set; } } diff --git a/src/BlazorUI/Demo/Shared/Exceptions/RestException.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/RestException.cs similarity index 93% rename from src/BlazorUI/Demo/Shared/Exceptions/RestException.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/RestException.cs index ec4a13c34e..b59bbfda04 100644 --- a/src/BlazorUI/Demo/Shared/Exceptions/RestException.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/RestException.cs @@ -5,7 +5,7 @@ namespace Bit.BlazorUI.Demo.Shared.Exceptions; public class RestException : KnownException { public RestException() - : base(nameof(AppStrings.RestException)) + : base(nameof(RestException)) { } diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ServerConnectionException.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ServerConnectionException.cs new file mode 100644 index 0000000000..1c973c8cc1 --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/ServerConnectionException.cs @@ -0,0 +1,18 @@ +namespace Bit.BlazorUI.Demo.Shared.Exceptions; +public class ServerConnectionException : UnknownException +{ + public ServerConnectionException() + : base(nameof(ServerConnectionException)) + { + } + + public ServerConnectionException(string message) + : base(message) + { + } + + public ServerConnectionException(string message, Exception innerException) + : base(message, innerException) + { + } +} diff --git a/src/BlazorUI/Demo/Shared/Exceptions/TooManyRequestsExceptions.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/TooManyRequestsExceptions.cs similarity index 92% rename from src/BlazorUI/Demo/Shared/Exceptions/TooManyRequestsExceptions.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/TooManyRequestsExceptions.cs index 0442b00ad5..9f4ae6a464 100644 --- a/src/BlazorUI/Demo/Shared/Exceptions/TooManyRequestsExceptions.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/TooManyRequestsExceptions.cs @@ -5,7 +5,7 @@ namespace Bit.BlazorUI.Demo.Shared.Exceptions; public class TooManyRequestsExceptions : RestException { public TooManyRequestsExceptions() - : base(nameof(AppStrings.TooManyRequestsExceptions)) + : base(nameof(TooManyRequestsExceptions)) { } diff --git a/src/BlazorUI/Demo/Shared/Exceptions/UnauthorizedException.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/UnauthorizedException.cs similarity index 92% rename from src/BlazorUI/Demo/Shared/Exceptions/UnauthorizedException.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/UnauthorizedException.cs index af507fa081..c4e88fca63 100644 --- a/src/BlazorUI/Demo/Shared/Exceptions/UnauthorizedException.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/UnauthorizedException.cs @@ -5,7 +5,7 @@ namespace Bit.BlazorUI.Demo.Shared.Exceptions; public class UnauthorizedException : RestException { public UnauthorizedException() - : base(nameof(AppStrings.UnauthorizedException)) + : base(nameof(UnauthorizedException)) { } diff --git a/src/BlazorUI/Demo/Shared/Exceptions/UnknownException.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/UnknownException.cs similarity index 86% rename from src/BlazorUI/Demo/Shared/Exceptions/UnknownException.cs rename to src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/UnknownException.cs index 7a6a792652..8560abe7b8 100644 --- a/src/BlazorUI/Demo/Shared/Exceptions/UnknownException.cs +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Exceptions/UnknownException.cs @@ -3,7 +3,7 @@ public class UnknownException : Exception { public UnknownException() - : base(nameof(AppStrings.UnknownException)) + : base(nameof(UnknownException)) { } @@ -17,4 +17,3 @@ public UnknownException(string message, Exception innerException) { } } - diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Extensions/IServiceCollectionExtensions.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Extensions/IServiceCollectionExtensions.cs new file mode 100644 index 0000000000..f4a501a52c --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Extensions/IServiceCollectionExtensions.cs @@ -0,0 +1,11 @@ +namespace Microsoft.Extensions.DependencyInjection; + +public static class IServiceCollectionExtensions +{ + public static IServiceCollection AddSharedServices(this IServiceCollection services) + { + // Services being registered here can get injected everywhere (Api, Web, Android, iOS, Windows and macOS) + + return services; + } +} diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Infra/BuildConfiguration.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Infra/BuildConfiguration.cs new file mode 100644 index 0000000000..ea81a459bf --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Infra/BuildConfiguration.cs @@ -0,0 +1,23 @@ +namespace Bit.BlazorUI.Demo.Shared.Infra; + +public static class BuildConfiguration +{ + public static bool IsDebug() + { +#if DEBUG + return true; +#else + return false; +#endif + } + + + public static bool IsRelease() + { +#if DEBUG + return false; +#else + return true; +#endif + } +} diff --git a/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Mapper.cs b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Mapper.cs new file mode 100644 index 0000000000..4fa72469da --- /dev/null +++ b/src/BlazorUI/Demo/Bit.BlazorUI.Demo.Shared/Mapper.cs @@ -0,0 +1,17 @@ +using Riok.Mapperly.Abstractions; + +namespace Bit.BlazorUI.Demo.Shared; + +/// +/// Patching methods help you patch the DTO you have received from the server (for example, after calling an Update api) +/// onto the DTO you have bound to the UI. This way, the UI gets updated with the latest saved changes, +/// and there's no need to re-fetch that specific data from the server. +/// For complete end to end sample you can check EditProfilePage.razor.cs +/// You can add as many as Patch methods you want for other DTO classes here. +/// For more information and to learn about customizing the mapping process, visit the website below: +/// https://mapperly.riok.app/docs/intro/ +/// +[Mapper(UseDeepCloning = true)] +public static partial class Mapper +{ +} diff --git a/src/BlazorUI/Demo/Client/App/Extensions/IServiceCollectionExtensions.cs b/src/BlazorUI/Demo/Client/App/Extensions/IServiceCollectionExtensions.cs deleted file mode 100644 index 0bb65bf690..0000000000 --- a/src/BlazorUI/Demo/Client/App/Extensions/IServiceCollectionExtensions.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Bit.BlazorUI.Demo.Client.App; -using Bit.BlazorUI.Demo.Client.App.Services; - -namespace Microsoft.Extensions.DependencyInjection; - -public static class IServiceCollectionExtensions -{ - public static IServiceCollection AddClientAppServices(this IServiceCollection services) - { - // Services being registered here can get injected in Android, iOS, Windows, and Mac. - -#if ANDROID - services.AddClientAndroidServices(); -#elif iOS - services.AddClientiOSServices(); -#elif Mac - services.AddClientMacServices(); -#elif Windows - services.AddClientWindowsServices(); -#endif - - services.AddScoped(); - services.AddSingleton(); - services.AddScoped(); - - return services; - } -} diff --git a/src/BlazorUI/Demo/Client/App/Platforms/Android/AndroidManifest.xml b/src/BlazorUI/Demo/Client/App/Platforms/Android/AndroidManifest.xml deleted file mode 100644 index d4a38147c9..0000000000 --- a/src/BlazorUI/Demo/Client/App/Platforms/Android/AndroidManifest.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/App/Platforms/Android/MainActivity.cs b/src/BlazorUI/Demo/Client/App/Platforms/Android/MainActivity.cs deleted file mode 100644 index 7f28227faf..0000000000 --- a/src/BlazorUI/Demo/Client/App/Platforms/Android/MainActivity.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Android.App; -using Android.Content.PM; - -namespace Bit.BlazorUI.Demo.Client.App.Platforms.Android; - -[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)] -public class MainActivity : MauiAppCompatActivity -{ -} diff --git a/src/BlazorUI/Demo/Client/App/Platforms/Tizen/tizen-manifest.xml b/src/BlazorUI/Demo/Client/App/Platforms/Tizen/tizen-manifest.xml deleted file mode 100644 index c24626f996..0000000000 --- a/src/BlazorUI/Demo/Client/App/Platforms/Tizen/tizen-manifest.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - appicon.xhigh.png - - - - - http://tizen.org/privilege/internet - - - - \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/App/Services/AppExceptionHandler.cs b/src/BlazorUI/Demo/Client/App/Services/AppExceptionHandler.cs deleted file mode 100644 index 67e62ad7a6..0000000000 --- a/src/BlazorUI/Demo/Client/App/Services/AppExceptionHandler.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Microsoft.AppCenter.Crashes; - -namespace Bit.BlazorUI.Demo.Client.App.Services; - -public partial class AppExceptionHandler : ExceptionHandlerBase -{ - public override void Handle(Exception exception, IDictionary? parameters = null) - { - Crashes.TrackError(exception, parameters?.ToDictionary(p => p.Key, p => p.Value?.ToString())); - - base.Handle(exception, parameters); - } -} diff --git a/src/BlazorUI/Demo/Client/Core/Bit.BlazorUI.Demo.Client.Core.csproj b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Bit.BlazorUI.Demo.Client.Core.csproj similarity index 67% rename from src/BlazorUI/Demo/Client/Core/Bit.BlazorUI.Demo.Client.Core.csproj rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Bit.BlazorUI.Demo.Client.Core.csproj index f09c5be59f..fdc3a3da87 100644 --- a/src/BlazorUI/Demo/Client/Core/Bit.BlazorUI.Demo.Client.Core.csproj +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Bit.BlazorUI.Demo.Client.Core.csproj @@ -1,10 +1,7 @@  - net8.0 - true - enable - enable + net8.0 BeforeBuildTasks; $(ResolveStaticWebAssetsInputsDependsOn) @@ -16,21 +13,18 @@ - - - - - - - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -38,30 +32,21 @@ - - - - + + - - - - - - - - - - - - - + + + + + + diff --git a/src/BlazorUI/Demo/Client/Core/Components/AppComponentBase.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/AppComponentBase.cs similarity index 78% rename from src/BlazorUI/Demo/Client/Core/Components/AppComponentBase.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/AppComponentBase.cs index 62f4e4c3ce..74373805ba 100644 --- a/src/BlazorUI/Demo/Client/Core/Components/AppComponentBase.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/AppComponentBase.cs @@ -1,24 +1,31 @@ namespace Bit.BlazorUI.Demo.Client.Core.Components; -public partial class AppComponentBase : ComponentBase +public partial class AppComponentBase : ComponentBase, IDisposable { + [AutoInject] protected IJSRuntime JSRuntime = default!; + [AutoInject] protected HttpClient HttpClient = default!; - [AutoInject] protected IStateService StateService = default!; + /// + /// + /// + [AutoInject] protected IPrerenderStateService PrerenderStateService = default!; + /// + /// + /// [AutoInject] protected IPubSubService PubSubService = default!; [AutoInject] protected IConfiguration Configuration = default!; - [AutoInject] protected IJSRuntime JSRuntime { get; set; } = default!; - [AutoInject] protected NavigationManager NavigationManager = default!; - [AutoInject] protected IStringLocalizer Localizer = default!; + [AutoInject] protected IExceptionHandler ExceptionHandler = default!; - [AutoInject] protected IExceptionHandler ExceptionHandler { get; set; } = default!; + private readonly CancellationTokenSource cts = new(); + protected CancellationToken CurrentCancellationToken => cts.Token; - protected async sealed override Task OnInitializedAsync() + protected sealed override async Task OnInitializedAsync() { try { @@ -31,7 +38,7 @@ protected async sealed override Task OnInitializedAsync() } } - protected async sealed override Task OnParametersSetAsync() + protected sealed override async Task OnParametersSetAsync() { try { @@ -44,7 +51,15 @@ protected async sealed override Task OnParametersSetAsync() } } - protected async override Task OnAfterRenderAsync(bool firstRender) + /// + /// Replacement for which catches all possible exceptions in order to prevent app crash. + /// + protected virtual Task OnInitAsync() + { + return Task.CompletedTask; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { @@ -61,12 +76,9 @@ protected async override Task OnAfterRenderAsync(bool firstRender) await base.OnAfterRenderAsync(firstRender); } - /// - /// Replacement for which catches all possible exceptions in order to prevent app crash. - /// - protected virtual Task OnInitAsync() + protected sealed override void OnInitialized() { - return Task.CompletedTask; + base.OnInitialized(); } /// @@ -156,4 +168,10 @@ public virtual Func WrapHandled(Func func) } }; } + + public virtual void Dispose() + { + cts.Cancel(); + cts.Dispose(); + } } diff --git a/src/BlazorUI/Demo/Client/Core/Components/ComponentClassesTable.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentClassesTable.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/ComponentClassesTable.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentClassesTable.razor diff --git a/src/BlazorUI/Demo/Client/Core/Components/ComponentClassesTable.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentClassesTable.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/ComponentClassesTable.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentClassesTable.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Components/ComponentDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/ComponentDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Components/ComponentDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/ComponentDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Components/ComponentDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/ComponentDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Components/ComponentEnumsTable.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentEnumsTable.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/ComponentEnumsTable.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentEnumsTable.razor diff --git a/src/BlazorUI/Demo/Client/Core/Components/ComponentEnumsTable.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentEnumsTable.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/ComponentEnumsTable.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentEnumsTable.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Components/ComponentExampleBox.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentExampleBox.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/ComponentExampleBox.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentExampleBox.razor diff --git a/src/BlazorUI/Demo/Client/Core/Components/ComponentExampleBox.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentExampleBox.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/ComponentExampleBox.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentExampleBox.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Components/ComponentExampleBox.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentExampleBox.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/ComponentExampleBox.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentExampleBox.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Components/ComponentParametersTable.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentParametersTable.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/ComponentParametersTable.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentParametersTable.razor diff --git a/src/BlazorUI/Demo/Client/Core/Components/ComponentParametersTable.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentParametersTable.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/ComponentParametersTable.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/ComponentParametersTable.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Components/PageOutlet.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/PageOutlet.razor similarity index 93% rename from src/BlazorUI/Demo/Client/Core/Components/PageOutlet.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/PageOutlet.razor index 375b3588c0..1a253e9713 100644 --- a/src/BlazorUI/Demo/Client/Core/Components/PageOutlet.razor +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/PageOutlet.razor @@ -28,7 +28,7 @@ set { title = value; - PubSubService.Pub(PubSubMessages.PAGE_TITLE_CHANGED, title); + PubSubService.Publish(PubSubMessages.PAGE_TITLE_CHANGED, title); } } diff --git a/src/BlazorUI/Demo/Client/Core/Components/SideRail.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/SideRail.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/SideRail.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/SideRail.razor diff --git a/src/BlazorUI/Demo/Client/Core/Components/SideRail.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/SideRail.razor.cs similarity index 86% rename from src/BlazorUI/Demo/Client/Core/Components/SideRail.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/SideRail.razor.cs index 36b5506feb..70cbdb0db1 100644 --- a/src/BlazorUI/Demo/Client/Core/Components/SideRail.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/SideRail.razor.cs @@ -5,11 +5,11 @@ public partial class SideRail private string? activeItemId; [Parameter] public List Items { get; set; } = new List(); - protected override void OnInitialized() + protected override async Task OnInitAsync() { activeItemId = Items.FirstOrDefault()?.Id; - base.OnInitialized(); + await base.OnInitAsync(); } private async Task ScrollToItem(SideRailItem targetItem) diff --git a/src/BlazorUI/Demo/Client/Core/Components/SideRail.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/SideRail.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Components/SideRail.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Components/SideRail.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Extensions/IConfigurationBuilderExtensions.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Extensions/IConfigurationBuilderExtensions.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Extensions/IConfigurationBuilderExtensions.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Extensions/IConfigurationBuilderExtensions.cs diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IConfigurationExtensions.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Extensions/IConfigurationExtensions.cs similarity index 87% rename from src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IConfigurationExtensions.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Extensions/IConfigurationExtensions.cs index e88b29bed5..4bb315c1db 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IConfigurationExtensions.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Extensions/IConfigurationExtensions.cs @@ -1,5 +1,4 @@ -//-:cnd:noEmit -namespace Microsoft.Extensions.Configuration; +namespace Microsoft.Extensions.Configuration; public static class IConfigurationExtensions { public static string GetApiServerAddress(this IConfiguration configuration) diff --git a/src/BlazorUI/Demo/Client/Core/Extensions/IJSRuntimeExtensions.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Extensions/IJSRuntimeExtensions.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Extensions/IJSRuntimeExtensions.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Extensions/IJSRuntimeExtensions.cs index ff7197fc93..c33bb2053a 100644 --- a/src/BlazorUI/Demo/Client/Core/Extensions/IJSRuntimeExtensions.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Extensions/IJSRuntimeExtensions.cs @@ -1,4 +1,5 @@ namespace Microsoft.JSInterop; + public static class IJSRuntimeExtensions { public static async Task ToggleBodyOverflow(this IJSRuntime jsRuntime, bool isNavOpen) @@ -21,4 +22,3 @@ public static async Task ApplyBodyElementClasses(this IJSRuntime jsRuntime, List await jsRuntime.InvokeVoidAsync("applyBodyElementClasses", cssClasses, cssVariables); } } - diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Extensions/IServiceCollectionExtensions.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Extensions/IServiceCollectionExtensions.cs new file mode 100644 index 0000000000..d2be000908 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Extensions/IServiceCollectionExtensions.cs @@ -0,0 +1,68 @@ + +using Bit.BlazorUI.Demo.Client.Core.Services.HttpMessageHandlers; +using Microsoft.AspNetCore.Components.WebAssembly.Services; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class IServiceCollectionExtensions +{ + public static IServiceCollection AddClientSharedServices(this IServiceCollection services) + { + // Services registered in this class can be injected in client side (Web, Android, iOS, Windows, macOS) + + services.TryAddTransient(); + + services.TryAddSessioned(); + + services.TryAddTransient(); + services.TryAddTransient(); + services.TryAddTransient(); + services.TryAddTransient(); + + services.TryAddTransient(); + services.TryAddTransient(); + services.TryAddScoped(); + + services.AddBitBlazorUIServices(); + services.AddSharedServices(); + + return services; + } + + /// + /// Utilizing the AddSessioned method seamlessly configures the service to function as a singleton in BlazorHybrid, and BlazorWebAssembly + /// environments. Simultaneously, it employs per-scope registration for pre-rendering and BlazorServer scenarios + /// + public static IServiceCollection AddSessioned(this IServiceCollection services) + where TImplementation : class, TService + where TService : class + { + if (AppRenderMode.IsBlazorHybrid || OperatingSystem.IsBrowser()) + { + return services.AddSingleton(); + } + else + { + return services.AddScoped(); + } + } + + /// + /// + /// + public static IServiceCollection TryAddSessioned(this IServiceCollection services) + where TImplementation : class, TService + where TService : class + { + if (AppRenderMode.IsBlazorHybrid || OperatingSystem.IsBrowser()) + { + services.TryAddSingleton(); + } + else + { + services.TryAddScoped(); + } + + return services; + } +} diff --git a/src/BlazorUI/Demo/Client/Core/Helpers/CultureInfoHelper.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Helpers/CultureInfoHelper.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Helpers/CultureInfoHelper.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Helpers/CultureInfoHelper.cs diff --git a/src/BlazorUI/Demo/Client/Core/Models/ComponentEnumItem.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/ComponentEnumItem.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Models/ComponentEnumItem.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/ComponentEnumItem.cs diff --git a/src/BlazorUI/Demo/Client/Core/Models/ComponentParameter.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/ComponentParameter.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Models/ComponentParameter.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/ComponentParameter.cs diff --git a/src/BlazorUI/Demo/Client/Core/Models/ComponentSubClass.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/ComponentSubClass.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Models/ComponentSubClass.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/ComponentSubClass.cs diff --git a/src/BlazorUI/Demo/Client/Core/Models/ComponentSubEnum.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/ComponentSubEnum.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Models/ComponentSubEnum.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/ComponentSubEnum.cs diff --git a/src/BlazorUI/Demo/Client/Core/Models/LinkType.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/LinkType.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Models/LinkType.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/LinkType.cs diff --git a/src/BlazorUI/Demo/Client/Core/Models/PopularComponent.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/PopularComponent.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Models/PopularComponent.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/PopularComponent.cs diff --git a/src/BlazorUI/Demo/Client/Core/Models/SideRailItem.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/SideRailItem.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Models/SideRailItem.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Models/SideRailItem.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Accordion/BitAccordionDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Accordion/BitAccordionDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Accordion/BitAccordionDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Accordion/BitAccordionDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Accordion/BitAccordionDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Accordion/BitAccordionDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Accordion/BitAccordionDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Accordion/BitAccordionDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Accordion/BitAccordionDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Accordion/BitAccordionDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Accordion/BitAccordionDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Accordion/BitAccordionDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Badge/BitBadgeDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Badge/BitBadgeDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Badge/BitBadgeDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Badge/BitBadgeDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Badge/BitBadgeDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Badge/BitBadgeDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Badge/BitBadgeDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Badge/BitBadgeDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Badge/BitBadgeDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Badge/BitBadgeDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Badge/BitBadgeDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Badge/BitBadgeDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Breadcrumb/BitBreadcrumbDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Breadcrumb/BitBreadcrumbDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Breadcrumb/BitBreadcrumbDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Breadcrumb/BitBreadcrumbDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Breadcrumb/BitBreadcrumbDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Breadcrumb/BitBreadcrumbDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Breadcrumb/BitBreadcrumbDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Breadcrumb/BitBreadcrumbDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Breadcrumb/BitBreadcrumbDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Breadcrumb/BitBreadcrumbDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Breadcrumb/BitBreadcrumbDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Breadcrumb/BitBreadcrumbDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Breadcrumb/PageInfoModel.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Breadcrumb/PageInfoModel.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Breadcrumb/PageInfoModel.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Breadcrumb/PageInfoModel.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitActionButtonDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitActionButtonDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitActionButtonDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitActionButtonDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitActionButtonDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitActionButtonDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitActionButtonDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitActionButtonDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitActionButtonDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitActionButtonDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitActionButtonDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitActionButtonDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitButtonDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitButtonDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitButtonDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitButtonDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitButtonDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitButtonDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitButtonDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitButtonDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitButtonDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitButtonDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitButtonDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitButtonDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitCompoundButtonDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitCompoundButtonDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitCompoundButtonDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitCompoundButtonDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitCompoundButtonDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitCompoundButtonDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitCompoundButtonDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitCompoundButtonDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitCompoundButtonDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitCompoundButtonDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitCompoundButtonDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitCompoundButtonDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitIconButtonDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitIconButtonDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitIconButtonDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitIconButtonDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitIconButtonDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitIconButtonDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitIconButtonDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitIconButtonDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitIconButtonDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitIconButtonDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitIconButtonDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitIconButtonDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitToggleButtonDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitToggleButtonDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitToggleButtonDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitToggleButtonDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitToggleButtonDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitToggleButtonDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitToggleButtonDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitToggleButtonDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitToggleButtonDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitToggleButtonDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/BitToggleButtonDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/BitToggleButtonDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/BitButtonGroupDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/BitButtonGroupDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/BitButtonGroupDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/BitButtonGroupDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/BitButtonGroupDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/BitButtonGroupDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/BitButtonGroupDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/BitButtonGroupDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/BitButtonGroupDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/BitButtonGroupDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/BitButtonGroupDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/BitButtonGroupDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/ButtonGroupActionItem.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/ButtonGroupActionItem.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/ButtonGroupActionItem.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/ButtonGroupActionItem.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupCustomDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupCustomDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupCustomDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupCustomDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupCustomDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupCustomDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupCustomDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupCustomDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupItemDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupItemDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupItemDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupItemDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupItemDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupItemDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupItemDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupItemDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupOptionDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupOptionDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupOptionDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupOptionDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupOptionDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupOptionDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupOptionDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonGroup/_BitButtonGroupOptionDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonValidationModel.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonValidationModel.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/ButtonValidationModel.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/ButtonValidationModel.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/BitMenuButtonDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/BitMenuButtonDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/BitMenuButtonDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/BitMenuButtonDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/BitMenuButtonDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/BitMenuButtonDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/BitMenuButtonDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/BitMenuButtonDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/BitMenuButtonDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/BitMenuButtonDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/BitMenuButtonDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/BitMenuButtonDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/MenuActionItem.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/MenuActionItem.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/MenuActionItem.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/MenuActionItem.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonCustomDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonCustomDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonCustomDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonCustomDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonCustomDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonCustomDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonCustomDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonCustomDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonItemDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonItemDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonItemDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonItemDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonItemDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonItemDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonItemDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonItemDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonOptionDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonOptionDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonOptionDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonOptionDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonOptionDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonOptionDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonOptionDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Buttons/MenuButton/_BitMenuButtonOptionDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Carousel/BitCarouselDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Carousel/BitCarouselDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Carousel/BitCarouselDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Carousel/BitCarouselDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Carousel/BitCarouselDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Carousel/BitCarouselDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Carousel/BitCarouselDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Carousel/BitCarouselDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Carousel/BitCarouselDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Carousel/BitCarouselDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Carousel/BitCarouselDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Carousel/BitCarouselDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/BitChartDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/BitChartDemo.razor new file mode 100644 index 0000000000..6df6cda793 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/BitChartDemo.razor @@ -0,0 +1,35 @@ +@page "/components/chart" + +@inherits AppComponentBase + + +
+ @if (isLoadingAssemblies) + { + + } + else + { + + <_BitChartBarDemo /> + + <_BitChartHorizontalBarDemo /> + + <_BitChartStackedBarDemo /> + + <_BitChartLineDemo /> + + <_BitChartPieDemo /> + + <_BitChartDoughnutDemo /> + + <_BitChartTimeDemo /> + + } +
\ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/BitChartDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/BitChartDemo.razor.cs similarity index 77% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/BitChartDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/BitChartDemo.razor.cs index 77df2a7144..baaf3589ef 100644 --- a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/BitChartDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/BitChartDemo.razor.cs @@ -1,4 +1,6 @@ -namespace Bit.BlazorUI.Demo.Client.Core.Pages.Components.Chart; +using Microsoft.AspNetCore.Components.WebAssembly.Services; + +namespace Bit.BlazorUI.Demo.Client.Core.Pages.Components.Chart; public partial class BitChartDemo { @@ -68,4 +70,25 @@ public partial class BitChartDemo } } }; + + [AutoInject] LazyAssemblyLoader lazyAssemblyLoader = default!; + + private bool isLoadingAssemblies = true; + + protected async override Task OnInitAsync() + { + try + { + if (OperatingSystem.IsBrowser()) + { + await lazyAssemblyLoader.LoadAssembliesAsync(["Newtonsoft.Json.wasm", "System.Private.Xml.wasm", "System.Data.Common.wasm"]); + } + } + finally + { + isLoadingAssemblies = false; + } + + await base.OnInitAsync(); + } } diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/BitChartDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/BitChartDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/BitChartDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/BitChartDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/BitChartDemoColors.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/BitChartDemoColors.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/BitChartDemoColors.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/BitChartDemoColors.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/BitChartDemoUtils.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/BitChartDemoUtils.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/BitChartDemoUtils.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/BitChartDemoUtils.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/IListExtensions.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/IListExtensions.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/IListExtensions.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/IListExtensions.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartBarDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartBarDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartBarDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartBarDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartBarDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartBarDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartBarDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartBarDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartDoughnutDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartDoughnutDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartDoughnutDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartDoughnutDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartDoughnutDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartDoughnutDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartDoughnutDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartDoughnutDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartHorizontalBarDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartHorizontalBarDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartHorizontalBarDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartHorizontalBarDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartHorizontalBarDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartHorizontalBarDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartHorizontalBarDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartHorizontalBarDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartLineDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartLineDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartLineDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartLineDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartLineDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartLineDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartLineDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartLineDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartPieDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartPieDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartPieDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartPieDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartPieDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartPieDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartPieDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartPieDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartStackedBarDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartStackedBarDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartStackedBarDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartStackedBarDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartStackedBarDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartStackedBarDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartStackedBarDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartStackedBarDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartTimeDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartTimeDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartTimeDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartTimeDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartTimeDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartTimeDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/_BitChartTimeDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Chart/_BitChartTimeDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/ColorPicker/BitColorPickerDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/ColorPicker/BitColorPickerDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/ColorPicker/BitColorPickerDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/ColorPicker/BitColorPickerDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/ColorPicker/BitColorPickerDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/ColorPicker/BitColorPickerDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/ColorPicker/BitColorPickerDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/ColorPicker/BitColorPickerDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/ColorPicker/BitColorPickerDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/ColorPicker/BitColorPickerDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/ColorPicker/BitColorPickerDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/ColorPicker/BitColorPickerDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/DataGrid/BitDataGridDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/DataGrid/BitDataGridDemo.razor new file mode 100644 index 0000000000..6aebeed51a --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/DataGrid/BitDataGridDemo.razor @@ -0,0 +1,123 @@ +@page "/components/datagrid" +@page "/components/data-grid" + +@using Demo.Shared.Dtos.DataGridDemo +@inherits AppComponentBase +@inject HttpClient HttpClient +@inject NavigationManager NavManager + + + + + @if (isLoadingAssemblies) + { + + } + else + { + + +
+
+ + + + + + + + @(context.Code) + + + + + + +
+ +
+
+
+ + + +
+ + + + + + + + +
+
+
+ +
+
+
+
+ + + +
+ + + + + +
+
+
+ +
+
+
+
+ } +
+ +@code { + IQueryable allCountries; + BitDataGrid dataGrid; + BitDataGrid productsDataGrid; + BitDataGridItemsProvider foodRecallProvider; + BitDataGridItemsProvider productsItemsProvider; + BitDataGridPaginationState pagination = new() { ItemsPerPage = 7 }; + IQueryable FilteredItems => allCountries?.Where(x => x.Name.Contains(typicalSampleNameFilter, StringComparison.CurrentCultureIgnoreCase)); + + string typicalSampleNameFilter = string.Empty; + string _virtualSampleNameFilter = string.Empty; + + string VirtualSampleNameFilter + { + get => _virtualSampleNameFilter; + set + { + _virtualSampleNameFilter = value; + _ = dataGrid.RefreshDataAsync(); + } + } + + string _odataSampleNameFilter = string.Empty; + + string ODataSampleNameFilter + { + get => _odataSampleNameFilter; + set + { + _odataSampleNameFilter = value; + _ = productsDataGrid.RefreshDataAsync(); + } + } +} diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/DataGrid/BitDataGridDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/DataGrid/BitDataGridDemo.razor.cs similarity index 92% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/DataGrid/BitDataGridDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/DataGrid/BitDataGridDemo.razor.cs index d084162ebe..dc22ffe195 100644 --- a/src/BlazorUI/Demo/Client/Core/Pages/Components/DataGrid/BitDataGridDemo.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/DataGrid/BitDataGridDemo.razor.cs @@ -1,4 +1,7 @@ -namespace Bit.BlazorUI.Demo.Client.Core.Pages.Components.DataGrid; +using Bit.BlazorUI.Demo.Shared.Dtos.DataGridDemo; +using Microsoft.AspNetCore.Components.WebAssembly.Services; + +namespace Bit.BlazorUI.Demo.Client.Core.Pages.Components.DataGrid; public partial class BitDataGridDemo { @@ -339,6 +342,99 @@ also it's possible to add arbitrary Blazor components to your table cells. new CountryModel { Code = "VE", Name = "Venezuela", Medals = new MedalsModel { Gold = 1, Silver = 3, Bronze = 0 } }, }; + [AutoInject] LazyAssemblyLoader lazyAssemblyLoader = default!; + + private bool isLoadingAssemblies = true; + + protected async override Task OnInitAsync() + { + allCountries = _countries.AsQueryable(); + + foodRecallProvider = async req => + { + try + { + var query = new Dictionary + { + { "search",$"recalling_firm:\"{_virtualSampleNameFilter}\"" }, + { "skip", req.StartIndex }, + { "limit", req.Count } + }; + + var sort = req.GetSortByProperties().SingleOrDefault(); + + if (sort != default) + { + var sortByColumnName = sort.PropertyName switch + { + nameof(FoodRecall.ReportDate) => "report_date", + _ => throw new InvalidOperationException() + }; + + query.Add("sort", $"{sortByColumnName}:{(sort.Direction == BitDataGridSortDirection.Ascending ? "asc" : "desc")}"); + } + + var url = NavManager.GetUriWithQueryParameters("https://api.fda.gov/food/enforcement.json", query); + + var data = await HttpClient.GetFromJsonAsync(url, AppJsonContext.Default.FoodRecallQueryResult, req.CancellationToken); + + return BitDataGridItemsProviderResult.From(data!.Results, data!.Meta.Results.Total); + } + catch + { + return BitDataGridItemsProviderResult.From(new List { }, 0); + } + }; + + productsItemsProvider = async req => + { + try + { + // https://docs.microsoft.com/en-us/odata/concepts/queryoptions-overview + + var query = new Dictionary() + { + { "$top", req.Count ?? 50 }, + { "$skip", req.StartIndex } + }; + + if (string.IsNullOrEmpty(_odataSampleNameFilter) is false) + { + query.Add("$filter", $"contains(Name,'{_odataSampleNameFilter}')"); + } + + if (req.GetSortByProperties().Any()) + { + query.Add("$orderby", string.Join(", ", req.GetSortByProperties().Select(p => $"{p.PropertyName} {(p.Direction == BitDataGridSortDirection.Ascending ? "asc" : "desc")}"))); + } + + var url = NavManager.GetUriWithQueryParameters("Products/GetProducts", query); + + var data = await HttpClient.GetFromJsonAsync(url, AppJsonContext.Default.PagedResultProductDto); + + return BitDataGridItemsProviderResult.From(data!.Items, (int)data!.TotalCount); + } + catch + { + return BitDataGridItemsProviderResult.From(new List { }, 0); + } + }; + + try + { + if (OperatingSystem.IsBrowser()) + { + await lazyAssemblyLoader.LoadAssembliesAsync(["Newtonsoft.Json.wasm", "System.Private.Xml.wasm", "System.Data.Common.wasm"]); + } + } + finally + { + isLoadingAssemblies = false; + } + + await base.OnInitAsync(); + } + private readonly string example1RazorCode = @" + + + + + + + +"; + + private readonly string example6RazorCode = @" + + + + + + +
+ +
+
+ +
+ +
+
+ +
+ + +
+
+
+
+
+
+ +"; + private readonly string example6CsharpCode = @" +private bool isContentLoaded;"; +} diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Shimmer/BitShimmerDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Shimmer/BitShimmerDemo.razor.scss new file mode 100644 index 0000000000..bd05f5cc11 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Shimmer/BitShimmerDemo.razor.scss @@ -0,0 +1,36 @@ +.shimmer-container { + padding: 1rem 0; +} + +::deep { + .custom-content { + gap: 1.7rem; + width: 100%; + display: flex; + align-items: center; + } + + .custom-content .column { + gap: 0.5rem; + flex-flow: column; + align-items: start; + } + + .custom-class { + border-radius: 1rem; + box-shadow: aqua 0 0 1rem; + } + + .custom-root { + text-shadow: aqua 0 0 0.5rem; + } + + .custom-wrapper { + border: solid tomato; + border-radius: 0.5rem; + } + + .custom-shimmer { + background: linear-gradient(90deg, transparent, darkred, transparent); + } +} diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Slider/BitSliderDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Slider/BitSliderDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Slider/BitSliderDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Slider/BitSliderDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Slider/BitSliderDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Slider/BitSliderDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Slider/BitSliderDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Slider/BitSliderDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Slider/BitSliderDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Slider/BitSliderDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Slider/BitSliderDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Slider/BitSliderDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/SnackBar/BitSnackBarDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/SnackBar/BitSnackBarDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/SnackBar/BitSnackBarDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/SnackBar/BitSnackBarDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/SnackBar/BitSnackBarDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/SnackBar/BitSnackBarDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/SnackBar/BitSnackBarDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/SnackBar/BitSnackBarDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/SnackBar/BitSnackBarDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/SnackBar/BitSnackBarDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/SnackBar/BitSnackBarDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/SnackBar/BitSnackBarDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Spinner/BitSpinnerDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Spinner/BitSpinnerDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Spinner/BitSpinnerDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Spinner/BitSpinnerDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Spinner/BitSpinnerDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Spinner/BitSpinnerDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Spinner/BitSpinnerDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Spinner/BitSpinnerDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Spinner/BitSpinnerDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Spinner/BitSpinnerDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Spinner/BitSpinnerDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Spinner/BitSpinnerDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Stack/BitStackDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Stack/BitStackDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Stack/BitStackDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Stack/BitStackDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Stack/BitStackDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Stack/BitStackDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Stack/BitStackDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Stack/BitStackDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Stack/BitStackDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Stack/BitStackDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Stack/BitStackDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Stack/BitStackDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Sticky/BitStickyDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Sticky/BitStickyDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Sticky/BitStickyDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Sticky/BitStickyDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Sticky/BitStickyDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Sticky/BitStickyDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Sticky/BitStickyDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Sticky/BitStickyDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Sticky/BitStickyDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Sticky/BitStickyDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Sticky/BitStickyDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Sticky/BitStickyDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Swiper/BitSwiperDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Swiper/BitSwiperDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Swiper/BitSwiperDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Swiper/BitSwiperDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Swiper/BitSwiperDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Swiper/BitSwiperDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Swiper/BitSwiperDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Swiper/BitSwiperDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Swiper/BitSwiperDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Swiper/BitSwiperDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Swiper/BitSwiperDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Swiper/BitSwiperDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Tooltip/BitTooltipDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Tooltip/BitTooltipDemo.razor new file mode 100644 index 0000000000..20eedd4f4b --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Tooltip/BitTooltipDemo.razor @@ -0,0 +1,141 @@ +@page "/components/tooltip" + + + + + + +
+ Explore the fundamental use of BitTooltip with a simple hover interaction on a BitButton. +
+
+
+ + Hover over me + +
+
+
+ + + +
+ You can customize the Tooltip position to enhance the user experience. +
+
+
+
+ + Top + + + Right + +
+
+
+ + Left + + + Bottom + +
+
+
+
+ + + +
+ Empower customization by overriding default styles and classes, allowing tailored design modifications to suit specific UI requirements. +
+

+
Component's Style & Class:

+
+ +
+
Item 1
+
Item 2
+
Item 3
+
+
+
+


+
Styles & Classes:

+
+ + Hover over me + +

+ + Hover over me + +
+
+
+ + + +
Here are some examples of customizing the tooltip content.
+
+
+ + + + Hover over me + + +
+
+
+ + + +
Here are some examples of advanced usage of tooltip.
+
+
+
+ + Anchor + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+
+ +
diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Tooltip/BitTooltipDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Tooltip/BitTooltipDemo.razor.cs new file mode 100644 index 0000000000..7af16420b3 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Tooltip/BitTooltipDemo.razor.cs @@ -0,0 +1,386 @@ +namespace Bit.BlazorUI.Demo.Client.Core.Pages.Components.Tooltip; + +public partial class BitTooltipDemo +{ + private readonly List componentParameters = new() + { + new() + { + Name = "Anchor", + Type = "RenderFragment?", + DefaultValue = "null", + Description = "Child content of component, the content that the Tooltip will apply to." + }, + new() + { + Name = "ChildContent", + Type = "RenderFragment?", + DefaultValue = "null", + Description = "Child content of component, the content that the Tooltip will apply to." + }, + new() + { + Name = "Classes", + Type = "BitTooltipClassStyles?", + DefaultValue = "null", + Description = "Custom CSS classes for different parts of the BitTooltip.", + LinkType = LinkType.Link, + Href = "#tooltip-class-styles" + }, + new() + { + Name = "DefaultIsShown", + Type = "bool", + DefaultValue = "false", + Description = "Default value of the IsShown." + }, + new() + { + Name = "HideArrow", + Type = "bool", + DefaultValue = "false", + Description = "Hides the arrow of tooltip." + }, + new() + { + Name = "HideDelay", + Type = "int", + DefaultValue = "0", + Description = "Delay (in milliseconds) before hiding the tooltip." + }, + new() + { + Name = "IsShown", + Type = "bool", + DefaultValue = "false", + Description = "The visibility state of the tooltip." + }, + new() + { + Name = "IsShownChanged", + Type = "EventCallback", + DefaultValue = "", + Description = "" + }, + new() + { + Name = "Position", + Type = "BitTooltipPosition", + DefaultValue = "BitTooltipPosition.Top", + Description = "The position of tooltip around its anchor.", + LinkType = LinkType.Link, + Href = "#tooltip-position-enum" + }, + new() + { + Name = "Template", + Type = "RenderFragment?", + DefaultValue = "null", + Description = "The content you want inside the tooltip." + }, + new() + { + Name = "Text", + Type = "string?", + DefaultValue = "null", + Description = "The text of tooltip to show." + }, + new() + { + Name = "ShowOnClick", + Type = "bool", + DefaultValue = "false", + Description = "Determines shows tooltip on click." + }, + new() + { + Name = "ShowDelay", + Type = "int", + DefaultValue = "0", + Description = "Delay (in milliseconds) before showing the tooltip." + }, + new() + { + Name = "ShowOnFocus", + Type = "bool", + DefaultValue = "false", + Description = "Determines shows tooltip on focus." + }, + new() + { + Name = "ShowOnHover", + Type = "bool", + DefaultValue = "true", + Description = "Determines shows tooltip on hover." + }, + new() + { + Name = "Styles", + Type = "BitTooltipClassStyles?", + DefaultValue = "null", + Description = "Custom CSS styles for different parts of the BitTooltip.", + LinkType = LinkType.Link, + Href = "#tooltip-class-styles" + } + }; + + private readonly List componentSubEnums = new() + { + new() + { + Id = "tooltip-position-enum", + Name = "BitTooltipPosition", + Description = "", + Items = new List() + { + new() + { + Name = "Top", + Value = "0", + Description = "The position of tooltip top of its anchor" + }, + new() + { + Name = "TopLeft", + Value = "1", + Description = "The position of tooltip top left of its anchor" + }, + new() + { + Name = "TopRight", + Value = "2", + Description = "The position of tooltip top right of its anchor" + }, + new() + { + Name = "RightTop", + Value = "3", + Description = "The position of tooltip right top of its anchor" + }, + new() + { + Name = "Right", + Value = "4", + Description = "The position of tooltip right of its anchor" + }, + new() + { + Name = "RightBottom", + Value = "5", + Description = "The position of tooltip right bottom of its anchor" + }, + new() + { + Name = "BottomRight", + Value = "6", + Description = "The position of tooltip bottom right of its anchor" + }, + new() + { + Name = "Bottom", + Value = "7", + Description = "The position of tooltip bottom of its anchor" + }, + new() + { + Name = "BottomLeft", + Value = "8", + Description = "The position of tooltip bottom left of its anchor" + }, + new() + { + Name = "LeftBottom", + Value = "9", + Description = "The position of tooltip left bottom of its anchor" + }, + new() + { + Name = "Left", + Value = "10", + Description = "The position of tooltip left of its anchor" + }, + new() + { + Name = "LeftTop", + Value = "11", + Description = "The position of tooltip left top of its anchor" + } + } + } + }; + + private readonly List componentSubClasses = new() + { + new() + { + Id = "tooltip-class-styles", + Title = "BitTooltipClassStyles", + Parameters = new() + { + new() + { + Name = "Root", + Type = "string?", + DefaultValue = "null", + Description = "Custom CSS classes/styles for the root element of the BitTooltip." + }, + new() + { + Name = "TooltipWrapper", + Type = "string?", + DefaultValue = "null", + Description = "Custom CSS classes/styles for the tooltip wrapper of the BitTooltip." + }, + new() + { + Name = "Tooltip", + Type = "string?", + DefaultValue = "null", + Description = "Custom CSS classes/styles for the tooltip of the BitTooltip." + }, + new() + { + Name = "Arrow", + Type = "string?", + DefaultValue = "null", + Description = "Custom CSS classes/styles for the arrow of the BitTooltip." + } + } + } + }; + + + + private BitTooltipPosition tooltipPosition; + private List> tooltipPositionList = Enum.GetValues(typeof(BitTooltipPosition)) + .Cast() + .Select(enumValue => new BitDropdownItem + { + Value = enumValue, + Text = enumValue.ToString() + }) + .ToList(); + + private bool isShown = true; + private bool showOnClick = true; + private bool showOnHover; + private bool hideArrow; + private double hideDelay = 800; + + + + private readonly string example1RazorCode = @" + + Hover over me +"; + + private readonly string example2RazorCode = @" + + Top + + + Right + + + Left + + + Bottom +"; + + private readonly string example3RazorCode = @" + + + + +
+
Item 1
+
Item 2
+
Item 3
+
+
+ + + + Hover over me + + + + Hover over me +"; + + private readonly string example4RazorCode = @" + + + + Hover over me + +"; + + private readonly string example5RazorCode = @" + + Anchor + + + + + + + +"; + private readonly string example5CsharpCode = @" +private bool isShown = true; +private bool showOnClick = true; +private bool showOnHover; +private bool hideArrow; +private double hideDelay = 800; + +private BitTooltipPosition tooltipPosition; + +private List> tooltipPositionList = Enum.GetValues(typeof(BitTooltipPosition)) + .Cast() + .Select(enumValue => new BitDropdownItem + { + Value = enumValue, + Text = enumValue.ToString() + }) + .ToList();"; +} diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Tooltip/BitTooltipDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Tooltip/BitTooltipDemo.razor.scss new file mode 100644 index 0000000000..387b835ca3 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Tooltip/BitTooltipDemo.razor.scss @@ -0,0 +1,44 @@ +.tooltips-container { + gap: 0.5rem; + display: flex; + padding-top: 1rem; + padding-left: 0.5rem; + max-width: max-content; + flex-flow: column wrap; + + &.center { + gap: 1.65rem; + display: flex; + max-width: unset; + min-height: 10rem; + flex-flow: row wrap; + align-items: center; + justify-content: center; + } +} + +::deep { + .custom-class .custom-content { + gap: 0.5rem; + padding: 0.5rem; + color: blueviolet; + border-radius: 1rem; + display: inline-flex; + box-shadow: aqua 0 0 0.5rem; + } + + .custom-root { + text-shadow: aqua 0 0 0.5rem; + } + + .custom-tooltip { + color: tomato; + border: solid tomato; + border-radius: 0.5rem; + } + + .custom-arrow { + border-right: solid tomato; + border-bottom: solid tomato; + } +} diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Typography/BitTypographyDemo.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Typography/BitTypographyDemo.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Typography/BitTypographyDemo.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Typography/BitTypographyDemo.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Typography/BitTypographyDemo.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Typography/BitTypographyDemo.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Typography/BitTypographyDemo.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Typography/BitTypographyDemo.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Typography/BitTypographyDemo.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Typography/BitTypographyDemo.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Components/Typography/BitTypographyDemo.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Typography/BitTypographyDemo.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/GettingStartedPage.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/GettingStartedPage.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/GettingStartedPage.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/GettingStartedPage.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/GettingStartedPage.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/GettingStartedPage.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/GettingStartedPage.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/GettingStartedPage.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/BenefitsSection.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/BenefitsSection.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/BenefitsSection.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/BenefitsSection.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/BenefitsSection.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/BenefitsSection.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/BenefitsSection.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/BenefitsSection.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/ComponentsSection.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor similarity index 97% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/ComponentsSection.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor index 8329f05290..4308f96b39 100644 --- a/src/BlazorUI/Demo/Client/Core/Pages/Home/ComponentsSection.razor +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor @@ -149,6 +149,9 @@ Spinner (BusyIndicator) + + Shimmer (Skeleton) + Loading @@ -170,6 +173,9 @@ ScrollablePane + + Tooltip +
Utilities diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/ComponentsSection.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/ComponentsSection.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/HeroSection.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/HeroSection.razor similarity index 95% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/HeroSection.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/HeroSection.razor index b95c73c2fe..09aab2bc41 100644 --- a/src/BlazorUI/Demo/Client/Core/Pages/Home/HeroSection.razor +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/HeroSection.razor @@ -5,10 +5,11 @@ bit BlazorUI bit BlazorUI components are native, easy-to-customize, and work seamlessly in all Blazor modes (WASM, Server, Hybrid, pre-rendering), saving you time and making development enjoyable.
- - - Get started   - + + Get started
diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/HeroSection.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/HeroSection.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/HeroSection.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/HeroSection.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/HeroSection.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/HeroSection.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/HeroSection.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/HeroSection.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/HomePage.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/HomePage.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/HomePage.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/HomePage.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/HomePage.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/HomePage.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/HomePage.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/HomePage.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/HomePage.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/HomePage.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/HomePage.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/HomePage.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/PopularComponents.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/PopularComponents.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/PopularComponents.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/PopularComponents.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/PopularComponents.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/PopularComponents.razor.cs similarity index 97% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/PopularComponents.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/PopularComponents.razor.cs index 457fbc8adc..2da81a40ad 100644 --- a/src/BlazorUI/Demo/Client/Core/Pages/Home/PopularComponents.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/PopularComponents.razor.cs @@ -40,11 +40,11 @@ public partial class PopularComponents }; private PopularComponent? SelectedComponent; - - protected override void OnInitialized() + + protected override async Task OnInitAsync() { SelectedComponent = Components[0]; - base.OnInitialized(); + await base.OnInitAsync(); } protected override async Task OnAfterRenderAsync(bool firstRender) diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/PopularComponents.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/PopularComponents.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/PopularComponents.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/PopularComponents.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/PopularComponentsIcon.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/PopularComponentsIcon.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/PopularComponentsIcon.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/PopularComponentsIcon.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Home/PopularComponentsIcon.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/PopularComponentsIcon.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/Home/PopularComponentsIcon.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/PopularComponentsIcon.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/IconographyPage.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/IconographyPage.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/IconographyPage.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/IconographyPage.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/IconographyPage.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/IconographyPage.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/IconographyPage.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/IconographyPage.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/IconographyPage.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/IconographyPage.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/IconographyPage.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/IconographyPage.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/OverviewPage.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/OverviewPage.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/OverviewPage.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/OverviewPage.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/OverviewPage.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/OverviewPage.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/OverviewPage.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/OverviewPage.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/TermsPage.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/TermsPage.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/TermsPage.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/TermsPage.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/TermsPage.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/TermsPage.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/TermsPage.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/TermsPage.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/TermsPage.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/TermsPage.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/TermsPage.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/TermsPage.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Pages/ThemingPage.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/ThemingPage.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/ThemingPage.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/ThemingPage.razor diff --git a/src/BlazorUI/Demo/Client/Core/Pages/ThemingPage.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/ThemingPage.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/ThemingPage.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/ThemingPage.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Pages/ThemingPage.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/ThemingPage.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Pages/ThemingPage.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/ThemingPage.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/App.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Routes.razor similarity index 59% rename from src/BlazorUI/Demo/Client/Core/App.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Routes.razor index eeb59594cb..2a22cc724e 100644 --- a/src/BlazorUI/Demo/Client/Core/App.razor +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Routes.razor @@ -1,9 +1,7 @@ bit BlazorUI - + AdditionalAssemblies="@(AssemblyLoadContext.Default.Assemblies.Where(asm => asm.GetName().Name?.Contains("Bit.BlazorUI.Demo") is true))"> @@ -11,7 +9,7 @@ - + \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Routes.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Routes.razor.cs new file mode 100644 index 0000000000..5c64a2c14f --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Routes.razor.cs @@ -0,0 +1,53 @@ +namespace Bit.BlazorUI.Demo.Client.Core; + +public partial class Routes +{ + [AutoInject] IJSRuntime jsRuntime = default!; + [AutoInject] IBitDeviceCoordinator bitDeviceCoordinator = default!; + + protected override async Task OnInitializedAsync() + { + if (AppRenderMode.IsBlazorHybrid) + { + await SetupBodyClasses(); + } + + await base.OnInitializedAsync(); + } + + private async Task SetupBodyClasses() + { + var cssClasses = new List { }; + + if (OperatingSystem.IsWindows()) + { + cssClasses.Add("bit-windows"); + } + else if (OperatingSystem.IsMacOS() || OperatingSystem.IsMacCatalyst()) + { + cssClasses.Add("bit-macos"); + } + else if (OperatingSystem.IsIOS() && OperatingSystem.IsMacCatalyst() is false) + { + cssClasses.Add("bit-ios"); + } + else if (OperatingSystem.IsAndroid()) + { + cssClasses.Add("bit-android"); + } + + var cssVariables = new Dictionary(); + var statusBarHeight = bitDeviceCoordinator.GetStatusBarHeight(); + + if (OperatingSystem.IsMacCatalyst() is false) + { + //For iOS this is handled in css using safe-area env() variables + //For Android there's an issue with keyboard in fullscreen mode. more info: https://github.com/bitfoundation/bitplatform/issues/5626 + //For Windows there's an issue with TitleBar. more info: https://github.com/bitfoundation/bitplatform/issues/5695 + statusBarHeight = 0; + } + + cssVariables.Add("--bit-status-bar-height", $"{statusBarHeight.ToString("F3", CultureInfo.InvariantCulture)}px"); + await jsRuntime.ApplyBodyElementClasses(cssClasses, cssVariables); + } +} diff --git a/src/BlazorUI/Demo/Client/Core/Scripts/app.ts b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Scripts/app.ts similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Scripts/app.ts rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Scripts/app.ts diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/AppRenderMode.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/AppRenderMode.cs new file mode 100644 index 0000000000..a71b0742dc --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/AppRenderMode.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Components.Web; +using OS = System.OperatingSystem; + +namespace Bit.BlazorUI.Demo.Client.Core.Services; + +public static class AppRenderMode +{ + public static readonly bool PrerenderEnabled = false; + + private static IComponentRenderMode Auto { get; } = new InteractiveAutoRenderMode(PrerenderEnabled); + private static IComponentRenderMode BlazorWebAssembly { get; } = new InteractiveWebAssemblyRenderMode(PrerenderEnabled); + private static IComponentRenderMode BlazorServer { get; } = new InteractiveServerRenderMode(PrerenderEnabled); + public static IComponentRenderMode NoPrerenderBlazorWebAssembly => new InteractiveWebAssemblyRenderMode(prerender: false); + + public static IComponentRenderMode Current => + BuildConfiguration.IsDebug() ? BlazorServer /*For better development experience*/ : Auto; + + public static bool PwaEnabled { get; } = +#if PwaEnabled + true; +#else + false; +#endif + + /// + /// Is running under .NET MAUI? + /// + public static bool IsBlazorHybrid { get; set; } +} diff --git a/src/BlazorUI/Demo/Client/Core/Services/Contracts/IBitDeviceCoordinator.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/Contracts/IBitDeviceCoordinator.cs similarity index 66% rename from src/BlazorUI/Demo/Client/Core/Services/Contracts/IBitDeviceCoordinator.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/Contracts/IBitDeviceCoordinator.cs index f54c53071a..e205ee419a 100644 --- a/src/BlazorUI/Demo/Client/Core/Services/Contracts/IBitDeviceCoordinator.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/Contracts/IBitDeviceCoordinator.cs @@ -1,4 +1,8 @@ namespace Bit.BlazorUI.Demo.Client.Core.Services.Contracts; + +/// +/// This service performs device-specific tasks, such as setting the theme. +/// public interface IBitDeviceCoordinator { public double GetStatusBarHeight() { return 0; } diff --git a/src/BlazorUI/Demo/Client/Core/Services/Contracts/IExceptionHandler.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/Contracts/IExceptionHandler.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Services/Contracts/IExceptionHandler.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/Contracts/IExceptionHandler.cs diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/Contracts/IPrerenderStateService.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/Contracts/IPrerenderStateService.cs new file mode 100644 index 0000000000..c400dfaf2f --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/Contracts/IPrerenderStateService.cs @@ -0,0 +1,17 @@ +namespace Bit.BlazorUI.Demo.Client.Core.Services.Contracts; + +/// +/// This service simplifies the process of persisting application state in Pre-Rendering mode +/// (explained in this documentation: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration#persist-prerendered-state). +/// If your project does not require prerendering to be enabled, you can completely remove this service and its usages from your project. +/// +public interface IPrerenderStateService +{ + /// + /// Instead of using ApplicationState.TryTakeFromJson, ApplicationState.RegisterOnPersisting, + /// and ApplicationState.PersistAsJson (explained here: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration#persist-prerendered-state), + /// one can easily use the following method () in the OnInit lifecycle method of the Blazor components or pages + /// to retrieve everything that requires an async-await (like current user's info). + /// + Task GetValue(string key, Func> factory); +} diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/Contracts/IPubSubService.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/Contracts/IPubSubService.cs new file mode 100644 index 0000000000..f41e14a100 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/Contracts/IPubSubService.cs @@ -0,0 +1,10 @@ +namespace Bit.BlazorUI.Demo.Client.Core.Services.Contracts; + +/// +/// Contract for Publish/Subscribe pattern. +/// +public interface IPubSubService +{ + void Publish(string message, object? payload); + Action Subscribe(string message, Func handler); +} diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/ExceptionHandlerBase.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/ExceptionHandlerBase.cs new file mode 100644 index 0000000000..02b051f15b --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/ExceptionHandlerBase.cs @@ -0,0 +1,24 @@ +using System.Diagnostics; + +namespace Bit.BlazorUI.Demo.Client.Core.Services; + +public abstract partial class ExceptionHandlerBase : IExceptionHandler +{ + [AutoInject] protected readonly MessageBoxService MessageBoxService = default!; + + public virtual void Handle(Exception exception, IDictionary? parameters = null) + { + var isDebug = BuildConfiguration.IsDebug(); + + string exceptionMessage = (exception as KnownException)?.Message ?? + (isDebug ? exception.ToString() : nameof(UnknownException)); + + if (isDebug) + { + _ = Console.Out.WriteLineAsync(exceptionMessage); + Debugger.Break(); + } + + _ = MessageBoxService.Show(exceptionMessage, "Error"); + } +} diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs new file mode 100644 index 0000000000..23d9108aa9 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs @@ -0,0 +1,49 @@ +using System.Net; + +namespace Bit.BlazorUI.Demo.Client.Core.Services.HttpMessageHandlers; + +public class ExceptionDelegatingHandler(HttpClientHandler httpClientHandler) + : DelegatingHandler(httpClientHandler) +{ + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + bool serverCommunicationSuccess = false; + + try + { + var response = await base.SendAsync(request, cancellationToken); + + serverCommunicationSuccess = true; + + if (response.IsSuccessStatusCode is false && response.Content.Headers.ContentType?.MediaType?.Contains("application/json", StringComparison.InvariantCultureIgnoreCase) is true) + { + if (response.Headers.TryGetValues("Request-ID", out IEnumerable? values) && values is not null && values.Any()) + { + RestErrorInfo restError = (await response!.Content.ReadFromJsonAsync(AppJsonContext.Default.RestErrorInfo, cancellationToken))!; + + Type exceptionType = typeof(RestErrorInfo).Assembly.GetType(restError.ExceptionType!) ?? typeof(UnknownException); + + var args = new List { typeof(KnownException).IsAssignableFrom(exceptionType) ? new LocalizedString(restError.Key!, restError.Message!) : restError.Message! }; + + if (exceptionType == typeof(ResourceValidationException)) + { + args.Add(restError.Payload); + } + + Exception exp = (Exception)Activator.CreateInstance(exceptionType, args.ToArray())!; + + throw exp; + } + } + + response.EnsureSuccessStatusCode(); + + return response; + } + catch (Exception exp) when ((exp is HttpRequestException && serverCommunicationSuccess is false) + || exp is TaskCanceledException tcExp && tcExp.InnerException is TimeoutException) + { + throw new ServerConnectionException(nameof(ServerConnectionException), exp); + } + } +} diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/HttpMessageHandlers/RequestHeadersDelegationHandler.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/HttpMessageHandlers/RequestHeadersDelegationHandler.cs new file mode 100644 index 0000000000..77cc0121fd --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/HttpMessageHandlers/RequestHeadersDelegationHandler.cs @@ -0,0 +1,17 @@ +using System.Net.Http.Headers; +using Microsoft.AspNetCore.Components.WebAssembly.Http; + +namespace Bit.BlazorUI.Demo.Client.Core.Services.HttpMessageHandlers; + +public class RequestHeadersDelegationHandler(RetryDelegatingHandler handler) + : DelegatingHandler(handler) +{ + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + request.SetBrowserRequestCredentials(BrowserRequestCredentials.Omit); + request.SetBrowserResponseStreamingEnabled(true); + + return await base.SendAsync(request, cancellationToken); + } +} + diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/HttpMessageHandlers/RetryDelegatingHandler.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/HttpMessageHandlers/RetryDelegatingHandler.cs new file mode 100644 index 0000000000..1310846e68 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/HttpMessageHandlers/RetryDelegatingHandler.cs @@ -0,0 +1,45 @@ +namespace Bit.BlazorUI.Demo.Client.Core.Services.HttpMessageHandlers; + +public class RetryDelegatingHandler(ExceptionDelegatingHandler handler) + : DelegatingHandler(handler) +{ + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var delays = GetDelays(scaleFirstTry: TimeSpan.FromSeconds(3), maxRetries: 3).ToArray(); + + Exception? lastExp = null; + + foreach (var delay in delays) + { + try + { + return await base.SendAsync(request, cancellationToken); + } + catch (Exception exp) when (exp is not KnownException) + { + lastExp = exp; + await Task.Delay(delay, cancellationToken); + } + } + + throw lastExp!; + } + + private static IEnumerable GetDelays(TimeSpan scaleFirstTry, int maxRetries) + { + TimeSpan maxValue = TimeSpan.MaxValue; + var maxTimeSpanDouble = maxValue.Ticks - 1_000.0; + var i = 0; + var targetTicksFirstDelay = scaleFirstTry.Ticks; + var num = 0.0; + for (; i < maxRetries; i++) + { + var num2 = i + Random.Shared.NextDouble(); + var next = Math.Pow(2.0, num2) * Math.Tanh(Math.Sqrt(4.0 * num2)); + var num3 = next - num; + yield return TimeSpan.FromTicks((long)Math.Min(num3 * 0.7_142_857_142_857_143 * targetTicksFirstDelay, maxTimeSpanDouble)); + num = next; + } + } +} diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/MessageBoxService.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/MessageBoxService.cs new file mode 100644 index 0000000000..478777fec9 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/MessageBoxService.cs @@ -0,0 +1,12 @@ +namespace Bit.BlazorUI.Demo.Client.Core.Services; +public partial class MessageBoxService +{ + [AutoInject] private IPubSubService pubSubService = default!; + + public async Task Show(string message, string title = "") + { + TaskCompletionSource tcs = new(); + pubSubService.Publish(PubSubMessages.SHOW_MESSAGE, (message, title, tcs)); + await tcs.Task; + } +} diff --git a/src/BlazorUI/Demo/Client/Core/Services/NavManuService.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/NavManuService.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Services/NavManuService.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/NavManuService.cs diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/PrerenderStateService.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/PrerenderStateService.cs new file mode 100644 index 0000000000..700653c1f0 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/PrerenderStateService.cs @@ -0,0 +1,55 @@ + +namespace Bit.BlazorUI.Demo.Client.Core.Services; + +/// +/// For more information docs. +/// +public class PrerenderStateService : IPrerenderStateService, IAsyncDisposable +{ + private PersistingComponentStateSubscription? subscription; + private readonly PersistentComponentState? persistentComponentState; + private readonly ConcurrentDictionary values = new(); + + public PrerenderStateService(PersistentComponentState? persistentComponentState = null) + { + subscription = persistentComponentState?.RegisterOnPersisting(PersistAsJson, AppRenderMode.Current); + this.persistentComponentState = persistentComponentState; + } + + public async Task GetValue(string key, Func> factory) + { + if (AppRenderMode.PrerenderEnabled is false) + return await factory(); + + if (persistentComponentState!.TryTakeFromJson(key, out T? value)) return value; + + var result = await factory(); + Persist(key, result); + return result; + } + + void Persist(string key, T value) + { + if (AppRenderMode.PrerenderEnabled is false) + return; + + values.TryRemove(key, out object? _); + values.TryAdd(key, value); + } + + async Task PersistAsJson() + { + foreach (var item in values) + { + persistentComponentState!.PersistAsJson(item.Key, item.Value); + } + } + + public async ValueTask DisposeAsync() + { + if (AppRenderMode.PrerenderEnabled is false) + return; + + subscription?.Dispose(); + } +} diff --git a/src/BlazorUI/Demo/Client/Core/Services/PubSubMessages.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/PubSubMessages.cs similarity index 74% rename from src/BlazorUI/Demo/Client/Core/Services/PubSubMessages.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/PubSubMessages.cs index 03c5bb6c6f..c3c0024482 100644 --- a/src/BlazorUI/Demo/Client/Core/Services/PubSubMessages.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/PubSubMessages.cs @@ -3,4 +3,5 @@ public static class PubSubMessages { public const string PAGE_TITLE_CHANGED = "PAGETITLECHANGED"; + public const string SHOW_MESSAGE = "SHOWMESSAGE"; } diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/PubSubService.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/PubSubService.cs new file mode 100644 index 0000000000..bec43d12a1 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Services/PubSubService.cs @@ -0,0 +1,34 @@ +namespace Bit.BlazorUI.Demo.Client.Core.Services; + +/// +/// For more information docs. +/// +public partial class PubSubService : IPubSubService +{ + [AutoInject] private IServiceProvider serviceProvider = default!; + + private readonly ConcurrentDictionary>> handlers = new(); + + public void Publish(string message, object? payload) + { + if (handlers.TryGetValue(message, out var messageHandlers)) + { + foreach (var handler in messageHandlers) + { + handler(payload) + .ContinueWith(t => serviceProvider.GetRequiredService().Handle(t.Exception!), TaskContinuationOptions.OnlyOnFaulted); + } + } + } + + public Action Subscribe(string message, Func handler) + { + var messageHandlers = handlers.ContainsKey(message) + ? handlers[message] + : handlers[message] = []; + + messageHandlers.Add(handler); + + return () => messageHandlers.Remove(handler); + } +} diff --git a/src/BlazorUI/Demo/Client/Core/Shared/AppErrorBoundary.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/AppErrorBoundary.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/AppErrorBoundary.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/AppErrorBoundary.razor diff --git a/src/BlazorUI/Demo/Client/Core/Shared/AppErrorBoundary.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/AppErrorBoundary.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/AppErrorBoundary.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/AppErrorBoundary.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Shared/AppErrorBoundary.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/AppErrorBoundary.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/AppErrorBoundary.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/AppErrorBoundary.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Shared/Footer.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/Footer.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/Footer.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/Footer.razor diff --git a/src/BlazorUI/Demo/Client/Core/Shared/Footer.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/Footer.razor.cs similarity index 86% rename from src/BlazorUI/Demo/Client/Core/Shared/Footer.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/Footer.razor.cs index 52d2e424cd..efc77f4d80 100644 --- a/src/BlazorUI/Demo/Client/Core/Shared/Footer.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/Footer.razor.cs @@ -12,14 +12,14 @@ public partial class Footer public string CurrentUrl { get; set; } - protected override void OnInitialized() + protected override async Task OnInitAsync() { try { SetCurrentUrl(); NavigationManager.LocationChanged += OnLocationChanged; - base.OnInitialized(); + await base.OnInitAsync(); } catch (Exception exp) { @@ -38,8 +38,9 @@ private void SetCurrentUrl() CurrentUrl = NavigationManager.Uri.Replace(NavigationManager.BaseUri, "/", StringComparison.InvariantCultureIgnoreCase); } - public void Dispose() + public override void Dispose() { NavigationManager.LocationChanged -= OnLocationChanged; + base.Dispose(); } } diff --git a/src/BlazorUI/Demo/Client/Core/Shared/Footer.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/Footer.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/Footer.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/Footer.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Shared/Header.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/Header.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/Header.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/Header.razor diff --git a/src/BlazorUI/Demo/Client/Core/Shared/Header.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/Header.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/Header.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/Header.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Shared/Header.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/Header.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/Header.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/Header.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Shared/LoadingComponent.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/LoadingComponent.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/LoadingComponent.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/LoadingComponent.razor diff --git a/src/BlazorUI/Demo/Client/Core/Shared/LoadingComponent.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/LoadingComponent.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/LoadingComponent.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/LoadingComponent.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Shared/MainLayout.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/MainLayout.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor diff --git a/src/BlazorUI/Demo/Client/Core/Shared/MainLayout.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.cs similarity index 91% rename from src/BlazorUI/Demo/Client/Core/Shared/MainLayout.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.cs index e187f6fab1..796030fd61 100644 --- a/src/BlazorUI/Demo/Client/Core/Shared/MainLayout.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.cs @@ -12,7 +12,7 @@ public partial class MainLayout : IDisposable private Action _unsubscribe = default!; private ErrorBoundary ErrorBoundaryRef = default!; - [AutoInject] private IStateService _stateService = default!; + [AutoInject] private IPrerenderStateService _prerenderStateService = default!; [AutoInject] private IPubSubService _pubSubService = default!; @@ -45,7 +45,7 @@ protected override void OnInitialized() _exceptionHandler.Handle(exp); } - _unsubscribe = _pubSubService.Sub(PubSubMessages.PAGE_TITLE_CHANGED, async payload => + _unsubscribe = _pubSubService.Subscribe(PubSubMessages.PAGE_TITLE_CHANGED, async payload => { _pageTitle = payload?.ToString(); await Task.Yield(); diff --git a/src/BlazorUI/Demo/Client/Core/Shared/MainLayout.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/MainLayout.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Shared/MessageBox.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MessageBox.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/MessageBox.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MessageBox.razor diff --git a/src/BlazorUI/Demo/Client/Core/Shared/MessageBox.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MessageBox.razor.cs similarity index 84% rename from src/BlazorUI/Demo/Client/Core/Shared/MessageBox.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MessageBox.razor.cs index 219e589534..64b5e9dc3c 100644 --- a/src/BlazorUI/Demo/Client/Core/Shared/MessageBox.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MessageBox.razor.cs @@ -19,11 +19,11 @@ public static async Task Show(string message, string title = "") await _tsc.Task; } - protected override void OnInitialized() + protected override async Task OnInitAsync() { OnShow += ShowMessageBox; - base.OnInitialized(); + await base.OnInitAsync(); } private async Task ShowMessageBox(string message, string title) @@ -52,5 +52,9 @@ private void OnOkClick() _tsc?.SetResult(null); } - public void Dispose() => OnShow -= ShowMessageBox; + public override void Dispose() + { + OnShow -= ShowMessageBox; + base.Dispose(); + } } diff --git a/src/BlazorUI/Demo/Client/Core/Shared/MessageBox.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MessageBox.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/MessageBox.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MessageBox.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Shared/NavMenu.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NavMenu.razor similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/NavMenu.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NavMenu.razor diff --git a/src/BlazorUI/Demo/Client/Core/Shared/NavMenu.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NavMenu.razor.cs similarity index 97% rename from src/BlazorUI/Demo/Client/Core/Shared/NavMenu.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NavMenu.razor.cs index 9c166c5ed8..67863b19b2 100644 --- a/src/BlazorUI/Demo/Client/Core/Shared/NavMenu.razor.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NavMenu.razor.cs @@ -95,6 +95,7 @@ public partial class NavMenu : IDisposable ChildItems = new() { new() { Text = "ProgressIndicator", Url = "/components/progressindicator", AdditionalUrls = new string[] { "/components/progress-indicator" } }, + new() { Text = "Shimmer", Url = "/components/shimmer", Description = "Skeleton" }, new() { Text = "Spinner", Url = "/components/spinner", Description = "Busy, Waiting, Loading" }, new() { Text = "Loading", Url = "/components/loading" } }, @@ -109,6 +110,7 @@ public partial class NavMenu : IDisposable new() { Text = "Modal", Url = "/components/modal" }, new() { Text = "Panel", Url = "/components/panel" }, new() { Text = "ScrollablePane", Url = "/components/scrollablepane", Description = "ScrollView" }, + new() { Text = "Tooltip", Url = "/components/tooltip" }, }, }, new() @@ -199,12 +201,14 @@ private async Task HandleOnItemClick(BitNavItem item) private static IEnumerable Flatten(IEnumerable e) => e.SelectMany(c => Flatten(c.ChildItems)).Concat(e); - public void Dispose() + public override void Dispose() { if (_disposed) return; _navMenuService.OnToggleMenu -= ToggleMenu; _disposed = true; + + base.Dispose(); } } diff --git a/src/BlazorUI/Demo/Client/Core/Shared/NavMenu.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NavMenu.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/NavMenu.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NavMenu.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Shared/NotFoundComponent.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NotFoundComponent.razor similarity index 71% rename from src/BlazorUI/Demo/Client/Core/Shared/NotFoundComponent.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NotFoundComponent.razor index 4ad8acfecb..2c2f2fa404 100644 --- a/src/BlazorUI/Demo/Client/Core/Shared/NotFoundComponent.razor +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NotFoundComponent.razor @@ -1,6 +1,6 @@ -@inherits AppComponentBase +@page "/not-found" - +@inherits AppComponentBase
diff --git a/src/BlazorUI/Demo/Client/Core/Shared/NotFoundComponent.razor.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NotFoundComponent.razor.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/NotFoundComponent.razor.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NotFoundComponent.razor.cs diff --git a/src/BlazorUI/Demo/Client/Core/Shared/NotFoundComponent.razor.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NotFoundComponent.razor.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Shared/NotFoundComponent.razor.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/NotFoundComponent.razor.scss diff --git a/src/BlazorUI/Demo/Client/Core/Styles/abstracts/_bit-css-variables.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Styles/abstracts/_bit-css-variables.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Styles/abstracts/_bit-css-variables.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Styles/abstracts/_bit-css-variables.scss diff --git a/src/BlazorUI/Demo/Client/Core/Styles/abstracts/_colors.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Styles/abstracts/_colors.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Styles/abstracts/_colors.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Styles/abstracts/_colors.scss diff --git a/src/BlazorUI/Demo/Client/Core/Styles/abstracts/_functions.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Styles/abstracts/_functions.scss similarity index 99% rename from src/BlazorUI/Demo/Client/Core/Styles/abstracts/_functions.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Styles/abstracts/_functions.scss index 29bd35e9c0..c2359935dd 100644 --- a/src/BlazorUI/Demo/Client/Core/Styles/abstracts/_functions.scss +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Styles/abstracts/_functions.scss @@ -12,4 +12,4 @@ $html-font-size: 16px; @function rem2($pxValue) { @return #{calc(stripUnit($pxValue) / stripUnit($html-font-size))}rem; -} +} \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Core/Styles/abstracts/_media-queries.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Styles/abstracts/_media-queries.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Styles/abstracts/_media-queries.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Styles/abstracts/_media-queries.scss diff --git a/src/BlazorUI/Demo/Client/Core/Styles/abstracts/_vars.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Styles/abstracts/_vars.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Styles/abstracts/_vars.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Styles/abstracts/_vars.scss diff --git a/src/BlazorUI/Demo/Client/Core/Styles/app.scss b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Styles/app.scss similarity index 100% rename from src/BlazorUI/Demo/Client/Core/Styles/app.scss rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Styles/app.scss diff --git a/src/BlazorUI/Demo/Client/Core/_Imports.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/_Imports.razor similarity index 63% rename from src/BlazorUI/Demo/Client/Core/_Imports.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/_Imports.razor index 3dff52602d..46574c1068 100644 --- a/src/BlazorUI/Demo/Client/Core/_Imports.razor +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/_Imports.razor @@ -1,19 +1,18 @@ @using System.Reflection +@using System.Runtime.Loader @using System.Globalization @using Microsoft.JSInterop -@using Microsoft.AspNetCore.Authorization -@using Microsoft.Extensions.Configuration +@using Microsoft.Extensions.Logging @using Microsoft.AspNetCore.Components +@using Microsoft.Extensions.Configuration @using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web.Virtualization @using Bit.BlazorUI @using Bit.BlazorUI.Demo -@using Bit.BlazorUI.Demo.Client.Core -@using Bit.BlazorUI.Demo.Client.Core.Pages -@using Bit.BlazorUI.Demo.Client.Core.Shared; -@using Bit.BlazorUI.Demo.Client.Core.Helpers -@using Bit.BlazorUI.Demo.Client.Core.Services @using Bit.BlazorUI.Demo.Client.Core.Components -@using Bit.BlazorUI.Demo.Client.Core.Services.Contracts \ No newline at end of file +@using Bit.BlazorUI.Demo.Client.Core.Shared +@using Bit.BlazorUI.Demo.Client.Core +@using Bit.BlazorUI.Demo.Client.Core.Services.Contracts +@using Bit.BlazorUI.Demo.Client.Core.Services \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/appsettings.json b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/appsettings.json new file mode 100644 index 0000000000..1205647c49 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/appsettings.json @@ -0,0 +1,3 @@ +{ + "ApiServerAddress": "http://localhost:5030/api/" // You can also use relative urls such as api/ for Blazor Server and WebAssembly +} diff --git a/src/BlazorUI/Demo/Client/Core/compilerconfig.json b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/compilerconfig.json similarity index 97% rename from src/BlazorUI/Demo/Client/Core/compilerconfig.json rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/compilerconfig.json index f7b136a7ab..29153edf7a 100644 --- a/src/BlazorUI/Demo/Client/Core/compilerconfig.json +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/compilerconfig.json @@ -383,6 +383,12 @@ "minify": { "enabled": false }, "options": { "sourceMap": false } }, + { + "outputFile": "Pages/Components/Shimmer/BitShimmerDemo.razor.css", + "inputFile": "Pages/Components/Shimmer/BitShimmerDemo.razor.scss", + "minify": { "enabled": false }, + "options": { "sourceMap": false } + }, { "outputFile": "Pages/Components/Slider/BitSliderDemo.razor.css", "inputFile": "Pages/Components/Slider/BitSliderDemo.razor.scss", @@ -419,6 +425,12 @@ "minify": { "enabled": false }, "options": { "sourceMap": false } }, + { + "outputFile": "Pages/Components/Tooltip/BitTooltipDemo.razor.css", + "inputFile": "Pages/Components/Tooltip/BitTooltipDemo.razor.scss", + "minify": { "enabled": false }, + "options": { "sourceMap": false } + }, { "outputFile": "Pages/Components/Typography/BitTypographyDemo.razor.css", "inputFile": "Pages/Components/Typography/BitTypographyDemo.razor.scss", diff --git a/src/BlazorUI/Demo/Client/Core/tsconfig.json b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/tsconfig.json similarity index 100% rename from src/BlazorUI/Demo/Client/Core/tsconfig.json rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/tsconfig.json diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/favicon.ico b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/favicon.ico similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/favicon.ico rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/favicon.ico diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/404.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/404.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/404.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/404.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/bit-logo-blue.png b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/bit-logo-blue.png similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/bit-logo-blue.png rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/bit-logo-blue.png diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/bit-logo.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/bit-logo.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/bit-logo.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/bit-logo.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/carousel/img1.jpg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/carousel/img1.jpg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/carousel/img1.jpg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/carousel/img1.jpg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/carousel/img2.jpg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/carousel/img2.jpg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/carousel/img2.jpg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/carousel/img2.jpg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/carousel/img3.jpg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/carousel/img3.jpg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/carousel/img3.jpg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/carousel/img3.jpg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/carousel/img4.jpg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/carousel/img4.jpg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/carousel/img4.jpg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/carousel/img4.jpg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/disconnected-cable.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/disconnected-cable.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/disconnected-cable.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/disconnected-cable.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/footer/github-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/footer/github-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/footer/github-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/footer/github-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/footer/linkedin-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/footer/linkedin-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/footer/linkedin-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/footer/linkedin-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/footer/location-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/footer/location-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/footer/location-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/footer/location-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/footer/tel-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/footer/tel-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/footer/tel-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/footer/tel-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/footer/twitter-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/footer/twitter-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/footer/twitter-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/footer/twitter-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/footer/youtube-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/footer/youtube-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/footer/youtube-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/footer/youtube-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/github-icon-dark.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/github-icon-dark.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/github-icon-dark.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/github-icon-dark.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/github-icon-light.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/github-icon-light.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/github-icon-light.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/github-icon-light.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/home/customize-icon.webp b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/home/customize-icon.webp similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/home/customize-icon.webp rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/home/customize-icon.webp diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/home/design-system-icon.webp b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/home/design-system-icon.webp similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/home/design-system-icon.webp rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/home/design-system-icon.webp diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/home/native-icon.webp b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/home/native-icon.webp similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/home/native-icon.webp rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/home/native-icon.webp diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/home/open-source-icon.webp b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/home/open-source-icon.webp similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/home/open-source-icon.webp rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/home/open-source-icon.webp diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/home/special-components-icon.webp b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/home/special-components-icon.webp similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/home/special-components-icon.webp rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/home/special-components-icon.webp diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/chevron-icon.webp b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/chevron-icon.webp similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/chevron-icon.webp rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/chevron-icon.webp diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/error-triangle.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/error-triangle.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/error-triangle.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/error-triangle.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/github-blue-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/github-blue-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/github-blue-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/github-blue-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/input-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/input-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/input-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/input-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/lists-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/lists-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/lists-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/lists-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/navs-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/navs-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/navs-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/navs-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/notifications-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/notifications-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/notifications-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/notifications-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/pickers-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/pickers-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/pickers-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/pickers-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/progrss-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/progrss-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/progrss-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/progrss-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/references-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/references-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/references-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/references-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/search-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/search-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/search-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/search-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/surfaces-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/surfaces-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/surfaces-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/surfaces-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/utilities-icon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/utilities-icon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icon/utilities-icon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icon/utilities-icon.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/icongraphy-empty-state-img.png b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icongraphy-empty-state-img.png similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/icongraphy-empty-state-img.png rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/icongraphy-empty-state-img.png diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/og-image.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/og-image.svg similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/og-image.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/og-image.svg diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/images/persona/persona-female.png b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/persona/persona-female.png similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/images/persona/persona-female.png rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/images/persona/persona-female.png diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/prism-1.28.0/prism-okaidia-bit.css b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/prism-1.28.0/prism-okaidia-bit.css new file mode 100644 index 0000000000..c6bf90ba8c --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/prism-1.28.0/prism-okaidia-bit.css @@ -0,0 +1 @@ +code[class*=language-],pre[class*=language-]{color:var(--bit-clr-fg-primary);background:0 0;text-shadow:0 0px rgba(0,0,0,.4);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:var(--bit-clr-bg-primary)}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8292a2}.token.punctuation{color:var(--bit-clr-fg-primary)}.token.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#a6e22e}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:var(--bit-clr-fg-primary)}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.important,.token.regex{color:#fd971f}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help} \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/prism-1.28.0/prism.js b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/prism-1.28.0/prism.js similarity index 100% rename from src/BlazorUI/Demo/Client/Core/wwwroot/prism-1.28.0/prism.js rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/wwwroot/prism-1.28.0/prism.js diff --git a/src/BlazorUI/Demo/Client/App/App.xaml b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/App.xaml similarity index 88% rename from src/BlazorUI/Demo/Client/App/App.xaml rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/App.xaml index 916f19c6c8..9f70ca9741 100644 --- a/src/BlazorUI/Demo/Client/App/App.xaml +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/App.xaml @@ -1,9 +1,9 @@  diff --git a/src/BlazorUI/Demo/Client/App/App.xaml.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/App.xaml.cs similarity index 84% rename from src/BlazorUI/Demo/Client/App/App.xaml.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/App.xaml.cs index d57d0901e9..431b343559 100644 --- a/src/BlazorUI/Demo/Client/App/App.xaml.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/App.xaml.cs @@ -1,6 +1,6 @@ [assembly: XamlCompilation(XamlCompilationOptions.Compile)] -namespace Bit.BlazorUI.Demo.Client.App; +namespace Bit.BlazorUI.Demo.Client.Maui; public partial class App { diff --git a/src/BlazorUI/Demo/Client/App/Bit.BlazorUI.Demo.Client.App.csproj b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Bit.BlazorUI.Demo.Client.Maui.csproj similarity index 87% rename from src/BlazorUI/Demo/Client/App/Bit.BlazorUI.Demo.Client.App.csproj rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Bit.BlazorUI.Demo.Client.Maui.csproj index d8bd363b58..364e45b868 100644 --- a/src/BlazorUI/Demo/Client/App/Bit.BlazorUI.Demo.Client.App.csproj +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Bit.BlazorUI.Demo.Client.Maui.csproj @@ -45,17 +45,25 @@ - + + + + + + + + + - + @@ -65,32 +73,30 @@ + - - - - - - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Extensions/IServiceCollectionExtensions.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Extensions/IServiceCollectionExtensions.cs new file mode 100644 index 0000000000..ae7f356eb6 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Extensions/IServiceCollectionExtensions.cs @@ -0,0 +1,30 @@ +using Bit.BlazorUI.Demo.Client.Maui; +using Bit.BlazorUI.Demo.Client.Maui.Services; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class IServiceCollectionExtensions +{ + public static IServiceCollection AddClientMauiServices(this IServiceCollection services) + { + // Services registered in this class can be injected in Android, iOS, Windows, and macOS. + + services.TryAddTransient(); + services.TryAddSingleton(); + services.TryAddTransient(); + +#if ANDROID + services.AddClientAndroidServices(); +#elif iOS + services.AddClientiOSServices(); +#elif Mac + services.AddClientMacServices(); +#elif Windows + services.AddClientWindowsServices(); +#endif + + services.AddClientSharedServices(); + + return services; + } +} diff --git a/src/BlazorUI/Demo/Client/App/MainPage.xaml b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/MainPage.xaml similarity index 86% rename from src/BlazorUI/Demo/Client/App/MainPage.xaml rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/MainPage.xaml index 446a2efac2..601158e4a2 100644 --- a/src/BlazorUI/Demo/Client/App/MainPage.xaml +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/MainPage.xaml @@ -1,5 +1,5 @@ + Default=#000000}}"> - + diff --git a/src/BlazorUI/Demo/Client/App/MainPage.xaml.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/MainPage.xaml.cs similarity index 53% rename from src/BlazorUI/Demo/Client/App/MainPage.xaml.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/MainPage.xaml.cs index 5a5505e8da..d4539d0cac 100644 --- a/src/BlazorUI/Demo/Client/App/MainPage.xaml.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/MainPage.xaml.cs @@ -1,14 +1,14 @@ -namespace Bit.BlazorUI.Demo.Client.App; +namespace Bit.BlazorUI.Demo.Client.Maui; public partial class MainPage { - private readonly IExceptionHandler _exceptionHandler; - private readonly IBitDeviceCoordinator _deviceCoordinator; + private readonly IExceptionHandler exceptionHandler; + private readonly IBitDeviceCoordinator deviceCoordinator; public MainPage(IExceptionHandler exceptionHandler, IBitDeviceCoordinator deviceCoordinator) { - _exceptionHandler = exceptionHandler; - _deviceCoordinator = deviceCoordinator; + this.exceptionHandler = exceptionHandler; + this.deviceCoordinator = deviceCoordinator; InitializeComponent(); @@ -16,25 +16,6 @@ public MainPage(IExceptionHandler exceptionHandler, IBitDeviceCoordinator device SetupStatusBar(); } - private async void ContentPage_Loaded(object sender, EventArgs e) - { - try - { -#if WINDOWS && RELEASE - var webView2 = (Microsoft.UI.Xaml.Controls.WebView2)blazorWebView.Handler!.PlatformView!; - await webView2.EnsureCoreWebView2Async(); - - var settings = webView2.CoreWebView2.Settings; - settings.IsZoomControlEnabled = false; - settings.AreBrowserAcceleratorKeysEnabled = false; -#endif - } - catch (Exception exp) - { - _exceptionHandler.Handle(exp); - } - } - private void SetupBlazorWebView() { BlazorWebViewHandler.BlazorWebViewMapper.AppendToMapping("CustomBlazorWebViewMapper", (handler, view) => @@ -48,16 +29,17 @@ private void SetupBlazorWebView() handler.PlatformView.Configuration.AllowsInlineMediaPlayback = true; handler.PlatformView.ScrollView.Bounces = false; - + handler.PlatformView.BackgroundColor = UIKit.UIColor.Clear; handler.PlatformView.Opaque = false; -#if DEBUG - if ((DeviceInfo.Current.Platform == DevicePlatform.MacCatalyst && DeviceInfo.Current.Version >= new Version(13, 3)) - || (DeviceInfo.Current.Platform == DevicePlatform.iOS && DeviceInfo.Current.Version >= new Version(16, 4))) + if (BuildConfiguration.IsDebug()) { - handler.PlatformView.SetValueForKey(Foundation.NSObject.FromObject(true), new Foundation.NSString("inspectable")); + if ((DeviceInfo.Current.Platform == DevicePlatform.MacCatalyst && DeviceInfo.Current.Version >= new Version(13, 3)) + || (DeviceInfo.Current.Platform == DevicePlatform.iOS && DeviceInfo.Current.Version >= new Version(16, 4))) + { + handler.PlatformView.SetValueForKey(Foundation.NSObject.FromObject(true), new Foundation.NSString("inspectable")); + } } -#endif #elif ANDROID handler.PlatformView.SetBackgroundColor(Android.Graphics.Color.Transparent); @@ -73,14 +55,36 @@ private void SetupBlazorWebView() settings.JavaScriptCanOpenWindowsAutomatically = settings.DomStorageEnabled = true; -#if DEBUG - settings.MixedContentMode = Android.Webkit.MixedContentHandling.AlwaysAllow; -#endif + if (BuildConfiguration.IsDebug()) + { + settings.MixedContentMode = Android.Webkit.MixedContentHandling.AlwaysAllow; + } settings.BlockNetworkLoads = settings.BlockNetworkImage = false; #endif }); + + Loaded += async delegate + { + try + { +#if WINDOWS + if (BuildConfiguration.IsRelease()) + { + var webView2 = (Microsoft.UI.Xaml.Controls.WebView2)blazorWebView.Handler!.PlatformView!; + await webView2.EnsureCoreWebView2Async(); + var settings = webView2.CoreWebView2.Settings; + settings.IsZoomControlEnabled = false; + settings.AreBrowserAcceleratorKeysEnabled = false; + } +#endif + } + catch (Exception exp) + { + exceptionHandler.Handle(exp); + } + }; } private void SetupStatusBar() @@ -89,11 +93,11 @@ private void SetupStatusBar() { try { - await _deviceCoordinator.ApplyTheme(AppInfo.Current.RequestedTheme is AppTheme.Dark); + await deviceCoordinator.ApplyTheme(AppInfo.Current.RequestedTheme is AppTheme.Dark); } catch (Exception exp) { - _exceptionHandler.Handle(exp); + exceptionHandler.Handle(exp); } }); } diff --git a/src/BlazorUI/Demo/Client/App/MauiProgram.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/MauiProgram.cs similarity index 64% rename from src/BlazorUI/Demo/Client/App/MauiProgram.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/MauiProgram.cs index 1c584d8547..094bdd7116 100644 --- a/src/BlazorUI/Demo/Client/App/MauiProgram.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/MauiProgram.cs @@ -1,15 +1,19 @@ -using System.Reflection; -using Microsoft.Extensions.FileProviders; + +using System.Reflection; +using Bit.BlazorUI.Demo.Client.Core.Services.HttpMessageHandlers; using Bit.BlazorUI.Demo.Client.Core.Shared; +using Bit.BlazorUI.Demo.Client.Maui.Services; -namespace Bit.BlazorUI.Demo.Client.App; +namespace Bit.BlazorUI.Demo.Client.Maui; public static class MauiProgram { - public static MauiAppBuilder CreateMauiAppBuilder() + public static MauiApp CreateMauiApp() { try { + AppRenderMode.IsBlazorHybrid = true; + // For MacCatalyst there are still some issues with AppCenter // https://github.com/microsoft/appcenter-sdk-dotnet/issues/1755 // https://github.com/microsoft/appcenter-sdk-dotnet/issues/1702 @@ -18,12 +22,8 @@ public static MauiAppBuilder CreateMauiAppBuilder() : OperatingSystem.IsAndroid() ? "c87802e3-0fa5-4938-b539-086b06d40726" : "f76345b1-9069-4477-afbe-a2be2a2ed46d"; Microsoft.AppCenter.AppCenter.Start(appSecret, typeof(Microsoft.AppCenter.Crashes.Crashes)); #endif - -#if !BlazorHybrid - throw new InvalidOperationException("Please switch to blazor hybrid as described in readme.md"); -#endif - var builder = MauiApp.CreateBuilder(); + var assembly = typeof(MainLayout).GetTypeInfo().Assembly; builder .UseMauiApp() @@ -32,26 +32,29 @@ public static MauiAppBuilder CreateMauiAppBuilder() var services = builder.Services; services.AddMauiBlazorWebView(); -#if DEBUG - services.AddBlazorWebViewDeveloperTools(); -#endif + + if (BuildConfiguration.IsDebug()) + { + services.AddBlazorWebViewDeveloperTools(); + } Uri.TryCreate(builder.Configuration.GetApiServerAddress(), UriKind.Absolute, out var apiServerAddress); - services.AddScoped(sp => + + services.AddTransient(sp => { - HttpClient httpClient = new(sp.GetRequiredService()) + var handler = sp.GetRequiredService(); + HttpClient httpClient = new(handler) { BaseAddress = apiServerAddress }; - return httpClient; }); - services.AddSharedServices(); - services.AddClientSharedServices(); - services.AddClientAppServices(); + services.AddClientMauiServices(); + + var mauiApp = builder.Build(); - return builder; + return mauiApp; } catch (Exception ex) { diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/AndroidManifest.xml b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/AndroidManifest.xml new file mode 100644 index 0000000000..458e80e9f0 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/App/Platforms/Android/Extensions/IServiceCollectionExtensions.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/Extensions/IServiceCollectionExtensions.cs similarity index 77% rename from src/BlazorUI/Demo/Client/App/Platforms/Android/Extensions/IServiceCollectionExtensions.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/Extensions/IServiceCollectionExtensions.cs index f0f2a2cfac..c669f4f455 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/Android/Extensions/IServiceCollectionExtensions.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/Extensions/IServiceCollectionExtensions.cs @@ -4,7 +4,7 @@ public static class IAndroidServiceCollectionExtensions { public static IServiceCollection AddClientAndroidServices(this IServiceCollection services) { - // Services being registered here can get injected in Android. + // Services registered in this class can be injected in Android. return services; } diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/MainActivity.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/MainActivity.cs new file mode 100644 index 0000000000..4370f26922 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/MainActivity.cs @@ -0,0 +1,10 @@ +using Android.App; +using Android.Content.PM; + +namespace Bit.BlazorUI.Demo.Client.Maui.Platforms.Android; + +[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, + ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)] +public class MainActivity : MauiAppCompatActivity +{ +} diff --git a/src/BlazorUI/Demo/Client/App/Platforms/Android/MainApplication.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/MainApplication.cs similarity index 73% rename from src/BlazorUI/Demo/Client/App/Platforms/Android/MainApplication.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/MainApplication.cs index 2d822654b2..b17be1231e 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/Android/MainApplication.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/MainApplication.cs @@ -4,12 +4,14 @@ [assembly: UsesPermission(Android.Manifest.Permission.Internet)] [assembly: UsesPermission(Android.Manifest.Permission.AccessNetworkState)] -namespace Bit.BlazorUI.Demo.Client.App.Platforms.Android; +namespace Bit.BlazorUI.Demo.Client.Maui.Platforms.Android; [Application( #if DEBUG - UsesCleartextTraffic = true + UsesCleartextTraffic = true, #endif + AllowBackup = true, + SupportsRtl = true )] public class MainApplication : MauiApplication { @@ -19,6 +21,5 @@ public MainApplication(IntPtr handle, JniHandleOwnership ownership) } protected override MauiApp CreateMauiApp() => MauiProgram - .CreateMauiAppBuilder() - .Build(); + .CreateMauiApp(); } diff --git a/src/BlazorUI/Demo/Client/App/Platforms/Android/Resources/values/colors.xml b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/Resources/values/colors.xml similarity index 100% rename from src/BlazorUI/Demo/Client/App/Platforms/Android/Resources/values/colors.xml rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Android/Resources/values/colors.xml diff --git a/src/BlazorUI/Demo/Client/App/Platforms/iOS/AppDelegate.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/AppDelegate.cs similarity index 67% rename from src/BlazorUI/Demo/Client/App/Platforms/iOS/AppDelegate.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/AppDelegate.cs index 3495f7ea0b..ff57926a96 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/iOS/AppDelegate.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/AppDelegate.cs @@ -1,9 +1,9 @@ using Foundation; -namespace Bit.BlazorUI.Demo.Client.App.Platforms.iOS; +namespace Bit.BlazorUI.Demo.Client.Maui.Platforms.MacCatalyst; [Register(nameof(AppDelegate))] public class AppDelegate : MauiUIApplicationDelegate { - protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAppBuilder().Build(); -} \ No newline at end of file + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); +} diff --git a/src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/Entitlements.Debug.plist b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/Entitlements.Debug.plist similarity index 100% rename from src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/Entitlements.Debug.plist rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/Entitlements.Debug.plist diff --git a/src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/Entitlements.Release.plist b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/Entitlements.Release.plist similarity index 100% rename from src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/Entitlements.Release.plist rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/Entitlements.Release.plist diff --git a/src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/Extensions/IServiceCollectionExtensions.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/Extensions/IServiceCollectionExtensions.cs similarity index 77% rename from src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/Extensions/IServiceCollectionExtensions.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/Extensions/IServiceCollectionExtensions.cs index a6f946e86b..0cc5d4fd3b 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/Extensions/IServiceCollectionExtensions.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/Extensions/IServiceCollectionExtensions.cs @@ -4,7 +4,7 @@ public static class IMacServiceCollectionExtensions { public static IServiceCollection AddClientMacServices(this IServiceCollection services) { - // Services being registered here can get injected in Mac. + // Services registered in this class can be injected in macOS. return services; } diff --git a/src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/Info.plist b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/Info.plist similarity index 100% rename from src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/Info.plist rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/Info.plist diff --git a/src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/Program.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/Program.cs similarity index 69% rename from src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/Program.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/Program.cs index 7526bb4ff4..d8ba922c69 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/Program.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/MacCatalyst/Program.cs @@ -1,6 +1,6 @@ using UIKit; -namespace Bit.BlazorUI.Demo.Client.App.Platforms.MacCatalyst; +namespace Bit.BlazorUI.Demo.Client.Maui.Platforms.MacCatalyst; public class Program { @@ -8,4 +8,4 @@ static void Main(string[] args) { UIApplication.Main(args, null, typeof(AppDelegate)); } -} \ No newline at end of file +} diff --git a/src/BlazorUI/Demo/Client/App/Platforms/Tizen/Main.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Tizen/Main.cs similarity index 70% rename from src/BlazorUI/Demo/Client/App/Platforms/Tizen/Main.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Tizen/Main.cs index b5e8439e36..299da7644a 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/Tizen/Main.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Tizen/Main.cs @@ -1,8 +1,8 @@ -namespace Bit.BlazorUI.Demo.Client.App; +namespace Bit.BlazorUI.Demo.Client.Maui; class Program : MauiApplication { - protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAppBuilder().CreateMauiApp(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); static void Main(string[] args) { diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Tizen/tizen-manifest.xml b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Tizen/tizen-manifest.xml new file mode 100644 index 0000000000..a1dbc43cc5 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Tizen/tizen-manifest.xml @@ -0,0 +1,15 @@ + + + + + + appicon.xhigh.png + + + + + http://tizen.org/privilege/internet + + + + \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/App/Platforms/Windows/App.xaml b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/App.xaml similarity index 75% rename from src/BlazorUI/Demo/Client/App/Platforms/Windows/App.xaml rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/App.xaml index e03a696d7e..9ee0382507 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/Windows/App.xaml +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/App.xaml @@ -1,5 +1,5 @@  diff --git a/src/BlazorUI/Demo/Client/App/Platforms/Windows/App.xaml.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/App.xaml.cs similarity index 63% rename from src/BlazorUI/Demo/Client/App/Platforms/Windows/App.xaml.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/App.xaml.cs index b3fab37c81..689a21642c 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/Windows/App.xaml.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/App.xaml.cs @@ -1,4 +1,4 @@ -namespace Bit.BlazorUI.Demo.Client.App.Platforms.Windows; +namespace Bit.BlazorUI.Demo.Client.Maui.Platforms.Windows; public partial class App { @@ -7,5 +7,5 @@ public App() InitializeComponent(); } - protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAppBuilder().Build(); + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } diff --git a/src/BlazorUI/Demo/Client/App/Platforms/Windows/Extensions/IServiceCollectionExtensions.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/Extensions/IServiceCollectionExtensions.cs similarity index 77% rename from src/BlazorUI/Demo/Client/App/Platforms/Windows/Extensions/IServiceCollectionExtensions.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/Extensions/IServiceCollectionExtensions.cs index f218d49a91..27419a2233 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/Windows/Extensions/IServiceCollectionExtensions.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/Extensions/IServiceCollectionExtensions.cs @@ -4,7 +4,7 @@ public static class IWindowsServiceCollectionExtensions { public static IServiceCollection AddClientWindowsServices(this IServiceCollection services) { - // Services being registered here can get injected in Windows. + // Services registered in this class can be injected in Windows. return services; } diff --git a/src/BlazorUI/Demo/Client/App/Platforms/Windows/Package.appxmanifest b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/Package.appxmanifest similarity index 100% rename from src/BlazorUI/Demo/Client/App/Platforms/Windows/Package.appxmanifest rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/Package.appxmanifest diff --git a/src/BlazorUI/Demo/Client/App/Platforms/Windows/app.manifest b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/app.manifest similarity index 87% rename from src/BlazorUI/Demo/Client/App/Platforms/Windows/app.manifest rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/app.manifest index b9e6bd003c..597605076f 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/Windows/app.manifest +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/Windows/app.manifest @@ -1,6 +1,6 @@ - + diff --git a/src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/AppDelegate.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/iOS/AppDelegate.cs similarity index 65% rename from src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/AppDelegate.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/iOS/AppDelegate.cs index 9acd0b7f82..a8aba8c3e6 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/MacCatalyst/AppDelegate.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/iOS/AppDelegate.cs @@ -1,9 +1,9 @@ using Foundation; -namespace Bit.BlazorUI.Demo.Client.App.Platforms.MacCatalyst; +namespace Bit.BlazorUI.Demo.Client.Maui.Platforms.iOS; [Register(nameof(AppDelegate))] public class AppDelegate : MauiUIApplicationDelegate { - protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiAppBuilder().Build(); -} \ No newline at end of file + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); +} diff --git a/src/BlazorUI/Demo/Client/App/Platforms/iOS/Extensions/IServiceCollectionExtensions.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/iOS/Extensions/IServiceCollectionExtensions.cs similarity index 77% rename from src/BlazorUI/Demo/Client/App/Platforms/iOS/Extensions/IServiceCollectionExtensions.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/iOS/Extensions/IServiceCollectionExtensions.cs index 2a1533edf9..16886245ef 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/iOS/Extensions/IServiceCollectionExtensions.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/iOS/Extensions/IServiceCollectionExtensions.cs @@ -4,7 +4,7 @@ public static class IiOSServiceCollectionExtensions { public static IServiceCollection AddClientiOSServices(this IServiceCollection services) { - // Services being registered here can get injected in iOS. + // Services registered in this class can be injected in iOS. return services; } diff --git a/src/BlazorUI/Demo/Client/App/Platforms/iOS/Info.plist b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/iOS/Info.plist similarity index 96% rename from src/BlazorUI/Demo/Client/App/Platforms/iOS/Info.plist rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/iOS/Info.plist index 2bda22bff2..f109f73b19 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/iOS/Info.plist +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/iOS/Info.plist @@ -15,7 +15,7 @@ arm64 - NSCameraUsageDescription + NSCameraUsageDescription This app uses camera for testing FileUpload component NSMicrophoneUsageDescription This app needs access to the microphone for record videos diff --git a/src/BlazorUI/Demo/Client/App/Platforms/iOS/Program.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/iOS/Program.cs similarity index 72% rename from src/BlazorUI/Demo/Client/App/Platforms/iOS/Program.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/iOS/Program.cs index b764ff9337..410d764a7e 100644 --- a/src/BlazorUI/Demo/Client/App/Platforms/iOS/Program.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Platforms/iOS/Program.cs @@ -1,6 +1,6 @@ using UIKit; -namespace Bit.BlazorUI.Demo.Client.App.Platforms.iOS; +namespace Bit.BlazorUI.Demo.Client.Maui.Platforms.iOS; public class Program { @@ -8,4 +8,4 @@ static void Main(string[] args) { UIApplication.Main(args, null, typeof(AppDelegate)); } -} \ No newline at end of file +} diff --git a/src/BlazorUI/Demo/Client/App/Properties/launchSettings.json b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Properties/launchSettings.json similarity index 100% rename from src/BlazorUI/Demo/Client/App/Properties/launchSettings.json rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Properties/launchSettings.json diff --git a/src/BlazorUI/Demo/Client/App/Resources/AppIcon/appicon.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Resources/AppIcon/appicon.svg similarity index 100% rename from src/BlazorUI/Demo/Client/App/Resources/AppIcon/appicon.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Resources/AppIcon/appicon.svg diff --git a/src/BlazorUI/Demo/Client/App/Resources/Raw/AboutAssets.txt b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Resources/Raw/AboutAssets.txt similarity index 100% rename from src/BlazorUI/Demo/Client/App/Resources/Raw/AboutAssets.txt rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Resources/Raw/AboutAssets.txt diff --git a/src/BlazorUI/Demo/Client/App/Resources/Splash/splash.svg b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Resources/Splash/splash.svg similarity index 100% rename from src/BlazorUI/Demo/Client/App/Resources/Splash/splash.svg rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Resources/Splash/splash.svg diff --git a/src/BlazorUI/Demo/Client/App/Services/AppDeviceCoordinator.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Services/MauiDeviceCoordinator.cs similarity index 90% rename from src/BlazorUI/Demo/Client/App/Services/AppDeviceCoordinator.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Services/MauiDeviceCoordinator.cs index 623b39d45c..e7351bbcdd 100644 --- a/src/BlazorUI/Demo/Client/App/Services/AppDeviceCoordinator.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Services/MauiDeviceCoordinator.cs @@ -1,6 +1,9 @@ -namespace Bit.BlazorUI.Demo.Client.App.Services; +namespace Bit.BlazorUI.Demo.Client.Maui.Services; -public class AppDeviceCoordinator : IBitDeviceCoordinator +/// +/// More info at +/// +public class MauiDeviceCoordinator : IBitDeviceCoordinator { public double GetStatusBarHeight() { diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Services/MauiExceptionHandler.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Services/MauiExceptionHandler.cs new file mode 100644 index 0000000000..986a329ed9 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/Services/MauiExceptionHandler.cs @@ -0,0 +1,22 @@ +using Microsoft.AppCenter.Crashes; + +namespace Bit.BlazorUI.Demo.Client.Maui.Services; + +/// +/// You can easily install AppCenter, Firebase Crashlytics, and other exception tracking libraries in your Client.Maui project. +/// Then, you can use their APIs to monitor all exceptions across Android, iOS, Windows, and macOS. +/// +public partial class MauiExceptionHandler : ExceptionHandlerBase +{ + public override void Handle(Exception exception, IDictionary? parameters = null) + { + if (exception is TaskCanceledException) + { + return; + } + + Crashes.TrackError(exception, parameters?.ToDictionary(p => p.Key, p => p.Value?.ToString())); + + base.Handle(exception, parameters); + } +} diff --git a/src/BlazorUI/Demo/Client/App/wwwroot/index.html b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/wwwroot/index.html similarity index 98% rename from src/BlazorUI/Demo/Client/App/wwwroot/index.html rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/wwwroot/index.html index 3b8d937d21..09fdc875a5 100644 --- a/src/BlazorUI/Demo/Client/App/wwwroot/index.html +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Maui/wwwroot/index.html @@ -11,7 +11,7 @@ - + @@ -19,8 +19,8 @@ - + @@ -30,7 +30,7 @@ body { background-color: #0D2960; } - + .lds-wrapper { top: 50%; left: 50%; @@ -108,6 +108,7 @@ animation-delay: -1.6s; } + @keyframes lds-grid { 0%, 100% { opacity: 1; @@ -120,8 +121,7 @@ - - + -
diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Bit.BlazorUI.Demo.Client.Web.csproj b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Bit.BlazorUI.Demo.Client.Web.csproj new file mode 100644 index 0000000000..69c87947c3 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Bit.BlazorUI.Demo.Client.Web.csproj @@ -0,0 +1,54 @@ + + + + net8.0 + + true + false + + true + true + + false + service-worker-assets.js + false + true + Default + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + diff --git a/src/BlazorUI/Demo/Client/Web/Pages/AppBswupProgressBar.razor b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Components/AppBswupProgressBar.razor similarity index 72% rename from src/BlazorUI/Demo/Client/Web/Pages/AppBswupProgressBar.razor rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Components/AppBswupProgressBar.razor index 8e8fcd4880..b494b59b7b 100644 --- a/src/BlazorUI/Demo/Client/Web/Pages/AppBswupProgressBar.razor +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Components/AppBswupProgressBar.razor @@ -1,5 +1,8 @@ @using Bit.Bswup @using Bit.BlazorUI +@using Bit.BlazorUI.Demo.Client.Core.Components + +@inherits AppComponentBase
@@ -69,5 +70,5 @@ - @* *@ + @* *@
\ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Web/Extensions/IServiceCollectionExtensions.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Extensions/IServiceCollectionExtensions.cs similarity index 59% rename from src/BlazorUI/Demo/Client/Web/Extensions/IServiceCollectionExtensions.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Extensions/IServiceCollectionExtensions.cs index adff068b40..fe358052fc 100644 --- a/src/BlazorUI/Demo/Client/Web/Extensions/IServiceCollectionExtensions.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Extensions/IServiceCollectionExtensions.cs @@ -6,9 +6,12 @@ public static class IServiceCollectionExtensions { public static IServiceCollection AddClientWebServices(this IServiceCollection services) { - // Services being registered here can get injected in web (blazor web assembly & blzor server) - services.AddScoped(); - services.AddScoped(); + // Services being registered here can get injected in web (blazor web assembly & blazor server) + + services.AddTransient(); + services.AddTransient(); + + services.AddClientSharedServices(); return services; } diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Program.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Program.cs new file mode 100644 index 0000000000..20b25c55a6 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Program.cs @@ -0,0 +1,21 @@ +using Bit.BlazorUI.Demo.Client.Core.Services.HttpMessageHandlers; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; + +var builder = WebAssemblyHostBuilder.CreateDefault(args); + +builder.Configuration.AddClientConfigurations(); + +Uri.TryCreate(builder.Configuration.GetApiServerAddress(), UriKind.RelativeOrAbsolute, out var apiServerAddress); + +if (apiServerAddress!.IsAbsoluteUri is false) +{ + apiServerAddress = new Uri($"{builder.HostEnvironment.BaseAddress}{apiServerAddress}"); +} + +builder.Services.AddTransient(sp => new HttpClient(sp.GetRequiredService()) { BaseAddress = apiServerAddress }); + +builder.Services.AddClientWebServices(); + +var host = builder.Build(); + +await host.RunAsync(); diff --git a/src/BlazorUI/Demo/Client/Web/Services/WebDeviceCoordinator.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Services/WebDeviceCoordinator.cs similarity index 100% rename from src/BlazorUI/Demo/Client/Web/Services/WebDeviceCoordinator.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Services/WebDeviceCoordinator.cs index 9def4628f3..ca9dae81f4 100644 --- a/src/BlazorUI/Demo/Client/Web/Services/WebDeviceCoordinator.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Services/WebDeviceCoordinator.cs @@ -1,5 +1,5 @@ namespace Bit.BlazorUI.Demo.Client.Web.Services; + public class WebDeviceCoordinator : IBitDeviceCoordinator { } - diff --git a/src/BlazorUI/Demo/Client/Web/Services/WebExceptionHandler.cs b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Services/WebExceptionHandler.cs similarity index 75% rename from src/BlazorUI/Demo/Client/Web/Services/WebExceptionHandler.cs rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Services/WebExceptionHandler.cs index 0265a3262a..3d9becc16b 100644 --- a/src/BlazorUI/Demo/Client/Web/Services/WebExceptionHandler.cs +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/Services/WebExceptionHandler.cs @@ -1,8 +1,14 @@ namespace Bit.BlazorUI.Demo.Client.Web.Services; + public partial class WebExceptionHandler : ExceptionHandlerBase { public override void Handle(Exception exception, IDictionary? parameters = null) { + if (exception is TaskCanceledException) + { + return; + } + base.Handle(exception, parameters); } } diff --git a/src/BlazorUI/Demo/Client/Web/wwwroot/favicon.ico b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/wwwroot/favicon.ico similarity index 100% rename from src/BlazorUI/Demo/Client/Web/wwwroot/favicon.ico rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/wwwroot/favicon.ico diff --git a/src/BlazorUI/Demo/Client/Web/wwwroot/images/icons/bit-icon-512.png b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/wwwroot/images/icons/bit-icon-512.png similarity index 100% rename from src/BlazorUI/Demo/Client/Web/wwwroot/images/icons/bit-icon-512.png rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/wwwroot/images/icons/bit-icon-512.png diff --git a/src/BlazorUI/Demo/Client/Web/wwwroot/manifest.json b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/wwwroot/manifest.json similarity index 99% rename from src/BlazorUI/Demo/Client/Web/wwwroot/manifest.json rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/wwwroot/manifest.json index ecc057169e..5618035f95 100644 --- a/src/BlazorUI/Demo/Client/Web/wwwroot/manifest.json +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/wwwroot/manifest.json @@ -47,4 +47,4 @@ "url": "/theming" } ] -} +} \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/wwwroot/service-worker.js b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/wwwroot/service-worker.js new file mode 100644 index 0000000000..0c4fa6ba58 --- /dev/null +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/wwwroot/service-worker.js @@ -0,0 +1,4 @@ +// In development, always fetch from the network and do not enable offline support. +// This is because caching would make development more difficult (changes would not +// be reflected on the first load after each change). +self.addEventListener('fetch', () => { }); \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Web/wwwroot/service-worker.published.js b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/wwwroot/service-worker.published.js similarity index 73% rename from src/BlazorUI/Demo/Client/Web/wwwroot/service-worker.published.js rename to src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/wwwroot/service-worker.published.js index a9df5bf956..32ecb3b655 100644 --- a/src/BlazorUI/Demo/Client/Web/wwwroot/service-worker.published.js +++ b/src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Web/wwwroot/service-worker.published.js @@ -1,16 +1,20 @@ -// bit version: 8.2.0 +// bit version: 8.3.0 // https://github.com/bitfoundation/bitplatform/tree/develop/src/Bswup +self.assetsInclude = []; self.assetsExclude = [ /bit\.blazorui\.fluent\.css$/, /bit\.blazorui\.fluent-dark\.css$/, /bit\.blazorui\.fluent-light\.css$/, + /Bit.BlazorUI.Demo\.Client\.Web\.styles\.css$/ ]; - self.externalAssets = [ { "url": "/" }, + { + "url": "_framework\/blazor.web.js" + }, { "url": "https://www.googletagmanager.com/gtag/js?id=G-G1ET5L69QF" } @@ -32,5 +36,6 @@ self.isPassive = true; self.defaultUrl = "/"; self.caseInsensitiveUrl = true; self.noPrerenderQuery = 'no-prerender=true'; +self.disablePassiveFirstBoot = true; -self.importScripts('_content/Bit.Bswup/bit-bswup.sw.js'); +self.importScripts('_content/Bit.Bswup/bit-bswup.sw.js'); \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Core/App.razor.cs b/src/BlazorUI/Demo/Client/Core/App.razor.cs deleted file mode 100644 index 8ae437b73e..0000000000 --- a/src/BlazorUI/Demo/Client/Core/App.razor.cs +++ /dev/null @@ -1,102 +0,0 @@ -using Microsoft.AspNetCore.Components.Routing; - -namespace Bit.BlazorUI.Demo.Client.Core; - -public partial class App -{ -#if BlazorWebAssembly && !BlazorHybrid - private List _lazyLoadedAssemblies = new(); - [AutoInject] private Microsoft.AspNetCore.Components.WebAssembly.Services.LazyAssemblyLoader _assemblyLoader = default!; -#endif - - [AutoInject] private IJSRuntime _jsRuntime = default!; - [AutoInject] private IBitDeviceCoordinator _bitDeviceCoordinator { get; set; } = default!; - - private bool _cultureHasNotBeenSet = true; - -#if BlazorHybrid - protected override async Task OnInitializedAsync() - { - SetupBodyClasses(); - await base.OnInitializedAsync(); - } -#else - protected override void OnAfterRender(bool firstRender) - { - if (firstRender) - { - SetupBodyClasses(); - } - - base.OnAfterRender(firstRender); - } -#endif - - private void SetupBodyClasses() - { - var cssClasses = new List(); - - if (BlazorModeDetector.Current.IsBlazorWebAssembly()) - { - cssClasses.Add("bit-blazor-wasm"); - } - else if (BlazorModeDetector.Current.IsBlazorServer()) - { - cssClasses.Add("bit-blazor-server"); - } - else if (BlazorModeDetector.Current.IsBlazorHybrid()) - { - cssClasses.Add("bit-blazor-hybrid"); - - if (OperatingSystem.IsWindows()) - { - cssClasses.Add("bit-windows"); - } - else if (OperatingSystem.IsLinux()) - { - cssClasses.Add("bit-linux"); - } - else if (OperatingSystem.IsMacOS() || OperatingSystem.IsMacCatalyst()) - { - cssClasses.Add("bit-macos"); - } - else if (OperatingSystem.IsIOS() && OperatingSystem.IsMacCatalyst() is false) - { - cssClasses.Add("bit-ios"); - } - else if (OperatingSystem.IsAndroid()) - { - cssClasses.Add("bit-android"); - } - } - else if (BlazorModeDetector.Current.IsBlazorElectron()) - { - cssClasses.Add("bit-blazor-electron"); - } - - var cssVariables = new Dictionary(); - var statusBarHeight = _bitDeviceCoordinator.GetStatusBarHeight(); - - if (OperatingSystem.IsMacCatalyst() is false) - { - //For iOS this is handled in css using safe-area env() variables - //For Android there's an issue with keyboard in fullscreen mode. more info: https://github.com/bitfoundation/bitplatform/issues/5626 - //For Windows there's an issue with TitleBar. more info: https://github.com/bitfoundation/bitplatform/issues/5695 - statusBarHeight = 0; - } - - cssVariables.Add("--bit-status-bar-height", $"{statusBarHeight.ToString("F3", CultureInfo.InvariantCulture)}px"); - _ = _jsRuntime.ApplyBodyElementClasses(cssClasses, cssVariables); - } - - private async Task OnNavigateAsync(NavigationContext args) - { -#if BlazorWebAssembly && !BlazorHybrid - if (args.Path.Contains("chart") && _lazyLoadedAssemblies.Any(asm => asm.GetName().Name == "Newtonsoft.Json") is false) - { - var assemblies = await _assemblyLoader.LoadAssembliesAsync(new[] { "Newtonsoft.Json.wasm", "System.Private.Xml.wasm", "System.Data.Common.wasm" }); - _lazyLoadedAssemblies.AddRange(assemblies); - } -#endif - } -} diff --git a/src/BlazorUI/Demo/Client/Core/Components/AppDataAnnotationsValidator.cs b/src/BlazorUI/Demo/Client/Core/Components/AppDataAnnotationsValidator.cs deleted file mode 100644 index e16f480c72..0000000000 --- a/src/BlazorUI/Demo/Client/Core/Components/AppDataAnnotationsValidator.cs +++ /dev/null @@ -1,182 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; -using Bit.BlazorUI.Demo.Shared.Attributes; -using Microsoft.AspNetCore.Components.Forms; - -namespace Bit.BlazorUI.Demo.Client.Core.Components; - -public partial class AppDataAnnotationsValidator : AppComponentBase, IDisposable -{ - private static readonly PropertyInfo _OtherPropertyNamePropertyInfo = typeof(CompareAttribute).GetProperty(nameof(CompareAttribute.OtherPropertyDisplayName))!; - - private bool _disposed; - private ValidationMessageStore _validationMessageStore = default!; - - [AutoInject] private IServiceProvider _serviceProvider = default!; - [AutoInject] private IStringLocalizerFactory _stringLocalizerFactory = default!; - - [CascadingParameter] private EditContext _editContext { get; set; } = default!; - - protected override Task OnInitAsync() - { - if (_editContext is null) - throw new InvalidOperationException("EditContext is required"); - - _editContext.OnFieldChanged += OnFieldChanged; - _editContext.OnValidationRequested += OnValidationRequested; - - _validationMessageStore = new ValidationMessageStore(_editContext); - - return base.OnInitAsync(); - } - - private void OnFieldChanged(object? sender, FieldChangedEventArgs eventArgs) - { - var fieldIdentifier = eventArgs.FieldIdentifier; - var propertyInfo = fieldIdentifier.Model.GetType().GetProperty(fieldIdentifier.FieldName); - if (propertyInfo is null) return; - - var propertyValue = propertyInfo.GetValue(fieldIdentifier.Model); - var validationContext = new ValidationContext(fieldIdentifier.Model, _serviceProvider, items: null) - { - MemberName = propertyInfo.Name - }; - var results = new List(); - - var parent = propertyInfo.DeclaringType!; - var dtoResourceTypeAttr = parent.GetCustomAttribute(); - if (dtoResourceTypeAttr is not null) - { - var resourceType = dtoResourceTypeAttr.ResourceType; - var stringLocalizer = _stringLocalizerFactory.Create(resourceType); - var validationAttributes = propertyInfo.GetCustomAttributes(); - - foreach (var attribute in validationAttributes) - { - if (string.IsNullOrWhiteSpace(attribute.ErrorMessageResourceName) is false && attribute.ErrorMessageResourceType is null) - { - attribute.ErrorMessageResourceType = resourceType; - var displayAttribute = propertyInfo.GetCustomAttribute(); - validationContext.DisplayName = stringLocalizer.GetString(displayAttribute?.Name ?? propertyInfo.Name); - - if (attribute is CompareAttribute compareAttribute) - { - var otherPropertyInfoDisplayAttribute = (parent.GetProperty(compareAttribute.OtherProperty) ?? throw new InvalidOperationException($"Invalid OtherProperty {compareAttribute.OtherProperty}")).GetCustomAttribute(); - _OtherPropertyNamePropertyInfo.SetValue(attribute, stringLocalizer.GetString(otherPropertyInfoDisplayAttribute?.Name ?? compareAttribute.OtherProperty).ToString()); - } - } - - var result = attribute.GetValidationResult(propertyValue, validationContext); - - if (result is not null) - { - results.Add(result); - } - } - - } - else - { - Validator.TryValidateProperty(propertyValue, validationContext, results); - } - - _validationMessageStore.Clear(fieldIdentifier); - foreach (var result in CollectionsMarshal.AsSpan(results)) - { - _validationMessageStore.Add(fieldIdentifier, result.ErrorMessage!); - } - - _editContext.NotifyValidationStateChanged(); - } - - private void OnValidationRequested(object? sender, ValidationRequestedEventArgs e) - { - var validationContext = new ValidationContext(_editContext.Model, _serviceProvider, items: null); - var results = new List(); - - var objectType = validationContext.ObjectType; - var objectInstance = validationContext.ObjectInstance; - var dtoResourceTypeAttr = objectType.GetCustomAttribute(); - - _validationMessageStore.Clear(); - if (dtoResourceTypeAttr is not null) - { - var resourceType = dtoResourceTypeAttr.ResourceType; - - var stringLocalizer = _stringLocalizerFactory.Create(resourceType); - - var properties = objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public); - - foreach (var propertyInfo in properties) - { - var context = new ValidationContext(objectInstance, validationContext, validationContext.Items); - context.MemberName = propertyInfo.Name; - var propertyValue = propertyInfo.GetValue(objectInstance); - var validationAttributes = propertyInfo.GetCustomAttributes(); - foreach (var attribute in validationAttributes) - { - if (string.IsNullOrWhiteSpace(attribute.ErrorMessageResourceName) is false && attribute.ErrorMessageResourceType is null) - { - attribute.ErrorMessageResourceType = resourceType; - var displayAttribute = propertyInfo.GetCustomAttribute(); - validationContext.DisplayName = stringLocalizer.GetString(displayAttribute?.Name ?? propertyInfo.Name); - if (attribute is CompareAttribute compareAttribute) - { - var otherPropertyInfoDisplayAttribute = (properties.FirstOrDefault(p => p.Name == compareAttribute.OtherProperty) ?? throw new InvalidOperationException($"Invalid OtherProperty {compareAttribute.OtherProperty}")).GetCustomAttribute(); - _OtherPropertyNamePropertyInfo.SetValue(attribute, stringLocalizer.GetString(otherPropertyInfoDisplayAttribute?.Name ?? compareAttribute.OtherProperty).ToString()); - } - } - - var result = attribute.GetValidationResult(propertyValue, context); - - if (result is not null) - { - results.Add(result); - } - } - } - } - else - { - Validator.TryValidateObject(_editContext.Model, validationContext, results, true); - } - - _validationMessageStore.Clear(); - foreach (var validationResult in results) - { - if (validationResult == null) continue; - - var hasMemberNames = false; - foreach (var memberName in validationResult.MemberNames) - { - hasMemberNames = true; - _validationMessageStore.Add(_editContext.Field(memberName), validationResult.ErrorMessage!); - } - - if (hasMemberNames) continue; - - _validationMessageStore.Add(new FieldIdentifier(_editContext.Model, fieldName: string.Empty), validationResult.ErrorMessage!); - } - - _editContext.NotifyValidationStateChanged(); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (_disposed || disposing is false) return; - - if (_editContext is not null) - { - _editContext.OnFieldChanged -= OnFieldChanged; - _editContext.OnValidationRequested -= OnValidationRequested; - } - - _disposed = true; - } -} diff --git a/src/BlazorUI/Demo/Client/Core/Extensions/IServiceCollectionExtensions.cs b/src/BlazorUI/Demo/Client/Core/Extensions/IServiceCollectionExtensions.cs deleted file mode 100644 index d6dac28a41..0000000000 --- a/src/BlazorUI/Demo/Client/Core/Extensions/IServiceCollectionExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Microsoft.Extensions.DependencyInjection; - -public static class IServiceCollectionExtensions -{ - public static IServiceCollection AddClientSharedServices(this IServiceCollection services) - { - services.AddScoped(); - services.AddScoped(); - - services.AddTransient(); - - services.AddScoped(); - - services.AddBitBlazorUIServices(); - - return services; - } -} diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/BitChartDemo.razor b/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/BitChartDemo.razor deleted file mode 100644 index 1436f2522c..0000000000 --- a/src/BlazorUI/Demo/Client/Core/Pages/Components/Chart/BitChartDemo.razor +++ /dev/null @@ -1,27 +0,0 @@ -@page "/components/chart" - - - -
- - <_BitChartBarDemo /> - - <_BitChartHorizontalBarDemo /> - - <_BitChartStackedBarDemo /> - - <_BitChartLineDemo /> - - <_BitChartPieDemo /> - - <_BitChartDoughnutDemo /> - - <_BitChartTimeDemo /> - -
\ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Core/Pages/Components/DataGrid/BitDataGridDemo.razor b/src/BlazorUI/Demo/Client/Core/Pages/Components/DataGrid/BitDataGridDemo.razor deleted file mode 100644 index 50169fafa5..0000000000 --- a/src/BlazorUI/Demo/Client/Core/Pages/Components/DataGrid/BitDataGridDemo.razor +++ /dev/null @@ -1,191 +0,0 @@ -@page "/components/datagrid" -@page "/components/data-grid" - -@using Demo.Shared.Dtos.DataGridDemo -@inject HttpClient HttpClient -@inject NavigationManager NavManager - - - - - - -
-
- - - - - - - - @(context.Code) - - - - - - -
- -
-
-
- - - -
- - - - - - - - -
-
-
- -
-
-
-
- - - -
- - - - - -
-
-
- -
-
-
-
- -
- -@code { - IQueryable allCountries; - BitDataGrid dataGrid; - BitDataGrid productsDataGrid; - BitDataGridItemsProvider foodRecallProvider; - BitDataGridItemsProvider productsItemsProvider; - BitDataGridPaginationState pagination = new() { ItemsPerPage = 7 }; - IQueryable FilteredItems => allCountries?.Where(x => x.Name.Contains(typicalSampleNameFilter, StringComparison.CurrentCultureIgnoreCase)); - - string typicalSampleNameFilter = string.Empty; - string _virtualSampleNameFilter = string.Empty; - - string VirtualSampleNameFilter - { - get => _virtualSampleNameFilter; - set - { - _virtualSampleNameFilter = value; - _ = dataGrid.RefreshDataAsync(); - } - } - - string _odataSampleNameFilter = string.Empty; - - string ODataSampleNameFilter - { - get => _odataSampleNameFilter; - set - { - _odataSampleNameFilter = value; - _ = productsDataGrid.RefreshDataAsync(); - } - } - - protected override async Task OnInitializedAsync() - { - allCountries = _countries.AsQueryable(); - - foodRecallProvider = async req => - { - try - { - var query = new Dictionary - { - { "search",$"recalling_firm:\"{_virtualSampleNameFilter}\"" }, - { "skip", req.StartIndex }, - { "limit", req.Count } - }; - - var sort = req.GetSortByProperties().SingleOrDefault(); - - if (sort != default) - { - var sortByColumnName = sort.PropertyName switch - { - nameof(FoodRecall.ReportDate) => "report_date", - _ => throw new InvalidOperationException() - }; - - query.Add("sort", $"{sortByColumnName}:{(sort.Direction == BitDataGridSortDirection.Ascending ? "asc" : "desc")}"); - } - - var url = NavManager.GetUriWithQueryParameters("https://api.fda.gov/food/enforcement.json", query); - - var data = await HttpClient.GetFromJsonAsync(url, AppJsonContext.Default.FoodRecallQueryResult, req.CancellationToken); - - return BitDataGridItemsProviderResult.From(data!.Results, data!.Meta.Results.Total); - } - catch - { - return BitDataGridItemsProviderResult.From(new List { }, 0); - } - }; - - productsItemsProvider = async req => - { - try - { - // https://docs.microsoft.com/en-us/odata/concepts/queryoptions-overview - - var query = new Dictionary() - { - { "$top", req.Count ?? 50 }, - { "$skip", req.StartIndex } - }; - - if (string.IsNullOrEmpty(_odataSampleNameFilter) is false) - { - query.Add("$filter", $"contains(Name,'{_odataSampleNameFilter}')"); - } - - if (req.GetSortByProperties().Any()) - { - query.Add("$orderby", string.Join(", ", req.GetSortByProperties().Select(p => $"{p.PropertyName} {(p.Direction == BitDataGridSortDirection.Ascending ? "asc" : "desc")}"))); - } - - var url = NavManager.GetUriWithQueryParameters("Products/GetProducts", query); - - var data = await HttpClient.GetFromJsonAsync(url, AppJsonContext.Default.PagedResultProductDto); - - return BitDataGridItemsProviderResult.From(data!.Items, (int)data!.TotalCount); - } - catch - { - return BitDataGridItemsProviderResult.From(new List { }, 0); - } - }; - } -} diff --git a/src/BlazorUI/Demo/Client/Core/Services/AppHttpClientHandler.cs b/src/BlazorUI/Demo/Client/Core/Services/AppHttpClientHandler.cs deleted file mode 100644 index 2c533e4cab..0000000000 --- a/src/BlazorUI/Demo/Client/Core/Services/AppHttpClientHandler.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Net; - -namespace Bit.BlazorUI.Demo.Client.Core.Services; - -public partial class AppHttpClientHandler : HttpClientHandler -{ - protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { - var response = await base.SendAsync(request, cancellationToken); - - if (response.StatusCode is HttpStatusCode.Unauthorized) - { - throw new UnauthorizedException(); - } - - if (response.IsSuccessStatusCode is false && response.Content.Headers.ContentType?.MediaType?.Contains("application/json", StringComparison.InvariantCultureIgnoreCase) is true) - { - if (response.Headers.TryGetValues("Request-ID", out IEnumerable? values) && values is not null && values.Any()) - { - RestErrorInfo restError = await response.Content.ReadFromJsonAsync(AppJsonContext.Default.RestErrorInfo); - - Type exceptionType = typeof(RestErrorInfo).Assembly.GetType(restError.ExceptionType) ?? typeof(UnknownException); - - var args = new List { typeof(KnownException).IsAssignableFrom(exceptionType) ? new LocalizedString(restError.Key!, restError.Message!) : restError.Message }; - - if (exceptionType == typeof(ResourceValidationException)) - { - args.Add(restError.Payload); - } - - Exception exp = (Exception)Activator.CreateInstance(exceptionType, args.ToArray()); - - throw exp; - } - } - - response.EnsureSuccessStatusCode(); - - return response; - } -} diff --git a/src/BlazorUI/Demo/Client/Core/Services/Contracts/IPubSubService.cs b/src/BlazorUI/Demo/Client/Core/Services/Contracts/IPubSubService.cs deleted file mode 100644 index 2e27e4c2f5..0000000000 --- a/src/BlazorUI/Demo/Client/Core/Services/Contracts/IPubSubService.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Bit.BlazorUI.Demo.Client.Core.Services.Contracts; - -public interface IPubSubService -{ - void Pub(string message, object? payload); - Action Sub(string message, Action handler); -} diff --git a/src/BlazorUI/Demo/Client/Core/Services/Contracts/IStateService.cs b/src/BlazorUI/Demo/Client/Core/Services/Contracts/IStateService.cs deleted file mode 100644 index c103f11b29..0000000000 --- a/src/BlazorUI/Demo/Client/Core/Services/Contracts/IStateService.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Bit.BlazorUI.Demo.Client.Core.Services.Contracts; - -public interface IStateService -{ - /// - /// Instead of using ApplicationState.TryTakeFromJson, ApplicationState.RegisterOnPersisting, and ApplicationState.PersistAsJson (explained here: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration#persist-prerendered-state), one can easily use the following method (StateService.GetValue) in the OnInit lifecycle method of the Blazor components or pages to retrieve everything that requires an async-await (like current user's info). - /// - Task GetValue(string key, Func> factory); -} diff --git a/src/BlazorUI/Demo/Client/Core/Services/ExceptionHandlerBase.cs b/src/BlazorUI/Demo/Client/Core/Services/ExceptionHandlerBase.cs deleted file mode 100644 index 73197d0c60..0000000000 --- a/src/BlazorUI/Demo/Client/Core/Services/ExceptionHandlerBase.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Diagnostics; - -namespace Bit.BlazorUI.Demo.Client.Core.Services; - -public abstract partial class ExceptionHandlerBase : IExceptionHandler -{ - [AutoInject] protected readonly IStringLocalizer Localizer = default!; - - public virtual void Handle(Exception exception, IDictionary? parameters = null) - { -#if DEBUG - string exceptionMessage = (exception as KnownException)?.Message ?? exception.ToString(); - _ = MessageBox.Show(exceptionMessage, Localizer[nameof(AppStrings.Error)]); - Console.WriteLine(exceptionMessage); - Debugger.Break(); -#else - if (exception is KnownException knownException) - { - _ = MessageBox.Show(knownException.Message, Localizer[nameof(AppStrings.Error)]); - } - else - { - _ = MessageBox.Show(Localizer[nameof(AppStrings.UnknownException)], Localizer[nameof(AppStrings.Error)]); - } -#endif - } -} diff --git a/src/BlazorUI/Demo/Client/Core/Services/PubSubService.cs b/src/BlazorUI/Demo/Client/Core/Services/PubSubService.cs deleted file mode 100644 index e3d10a6f2b..0000000000 --- a/src/BlazorUI/Demo/Client/Core/Services/PubSubService.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Bit.BlazorUI.Demo.Client.Core.Services; - -public class PubSubService : IPubSubService -{ - private readonly ConcurrentDictionary>> _handlers = new(); - - public void Pub(string message, object? payload) - { - if (_handlers.TryGetValue(message, out var handlers)) - { - handlers.ForEach(handler => handler(payload)); - } - } - - public Action Sub(string message, Action handler) - { - var handlers = _handlers.ContainsKey(message) - ? _handlers[message] - : _handlers[message] = new List>(); - - handlers.Add(handler); - - return () => handlers.Remove(handler); - } -} diff --git a/src/BlazorUI/Demo/Client/Core/Services/StateService.cs b/src/BlazorUI/Demo/Client/Core/Services/StateService.cs deleted file mode 100644 index c128bb249f..0000000000 --- a/src/BlazorUI/Demo/Client/Core/Services/StateService.cs +++ /dev/null @@ -1,59 +0,0 @@ - -namespace Bit.BlazorUI.Demo.Client.Core.Services; - -// Using this class, persisting the application state on Pre-Rendering mode (explained here: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration#persist-prerendered-state) will be very simple in this multi-mode Template project. - -#if (BlazorWebAssembly || BlazorServer) && (SpaPrerendered || PwaPrerendered) -public class StateService : IStateService, IAsyncDisposable -{ - private PersistingComponentStateSubscription? _subscription; - private readonly PersistentComponentState _applicationState; - private readonly ConcurrentDictionary _values = new ConcurrentDictionary(); - - public StateService(PersistentComponentState applicationState) - { - _applicationState = applicationState; - - if (OperatingSystem.IsBrowser() is false) - _subscription = applicationState.RegisterOnPersisting(PersistAsJson); - } - - public async Task GetValue(string key, Func> factory) - { - if (_applicationState.TryTakeFromJson(key, out T? value)) - return value; - var result = await factory(); - Persist(key, result); - return result; - } - - void Persist(string key, T value) - { - if (OperatingSystem.IsBrowser()) - return; - _values.TryRemove(key, out object? _); - _values.TryAdd(key, value); - } - - async Task PersistAsJson() - { - if (OperatingSystem.IsBrowser()) - return; - foreach (var item in _values) - _applicationState.PersistAsJson(item.Key, item.Value); - } - - public async ValueTask DisposeAsync() - { - _subscription?.Dispose(); - } -} -#else -public class StateService : IStateService -{ - public Task GetValue(string key, Func> factory) - { - return factory(); - } -} -#endif diff --git a/src/BlazorUI/Demo/Client/Core/Shared/ChangeResponseStatusCode.cs b/src/BlazorUI/Demo/Client/Core/Shared/ChangeResponseStatusCode.cs deleted file mode 100644 index c820290414..0000000000 --- a/src/BlazorUI/Demo/Client/Core/Shared/ChangeResponseStatusCode.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Net; - -namespace Bit.BlazorUI.Demo.Client.Core.Shared; - -public partial class ChangeResponseStatusCode : AppComponentBase -{ - [Parameter] - public HttpStatusCode StatusCode { get; set; } - - private static readonly Type? _httpContextAccessorType = Type.GetType("Microsoft.AspNetCore.Http.IHttpContextAccessor, Microsoft.AspNetCore.Http.Abstractions"); - - [AutoInject] - public IServiceProvider _serviceProvider = default!; - - protected override Task OnInitAsync() - { - if (_httpContextAccessorType is not null && BlazorModeDetector.Current.IsBlazorWebAssembly()) - { - var httpContextAccessor = _serviceProvider.GetService(_httpContextAccessorType); - - var httpContextProperty = _httpContextAccessorType.GetProperty("HttpContext")!; - - var httpContext = httpContextProperty.GetValue(httpContextAccessor)!; - - var response = httpContext.GetType().GetProperty("Response")!.GetValue(httpContext)!; - - response.GetType().GetProperty("StatusCode")!.SetValue(response, (int)StatusCode); - } - - return base.OnInitAsync(); - } -} diff --git a/src/BlazorUI/Demo/Client/Core/appsettings.json b/src/BlazorUI/Demo/Client/Core/appsettings.json deleted file mode 100644 index dbfca141cb..0000000000 --- a/src/BlazorUI/Demo/Client/Core/appsettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "DetailedErrors": true, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "AllowedHosts": "*", - "ApiServerAddress": "http://localhost:5000/api/" -} diff --git a/src/BlazorUI/Demo/Client/Core/wwwroot/prism-1.28.0/prism-okaidia-bit.css b/src/BlazorUI/Demo/Client/Core/wwwroot/prism-1.28.0/prism-okaidia-bit.css deleted file mode 100644 index 6cc5b16de4..0000000000 --- a/src/BlazorUI/Demo/Client/Core/wwwroot/prism-1.28.0/prism-okaidia-bit.css +++ /dev/null @@ -1 +0,0 @@ -code[class*=language-],pre[class*=language-]{color:var(--bit-clr-fg-primary);background:0 0;text-shadow:0 0px rgba(0,0,0,.4);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:var(--bit-clr-bg-primary)}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8292a2}.token.punctuation{color:var(--bit-clr-fg-primary)}.token.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#a6e22e}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:var(--bit-clr-fg-primary)}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.important,.token.regex{color:#fd971f}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help} diff --git a/src/BlazorUI/Demo/Client/Web/.config/dotnet-tools.json b/src/BlazorUI/Demo/Client/Web/.config/dotnet-tools.json deleted file mode 100644 index 5bd5ffbaef..0000000000 --- a/src/BlazorUI/Demo/Client/Web/.config/dotnet-tools.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": 1, - "isRoot": true, - "tools": { - "electronnet.cli": { - "version": "23.6.1", - "commands": [ - "electronize" - ] - } - } -} \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Web/Bit.BlazorUI.Demo.Client.Web.csproj b/src/BlazorUI/Demo/Client/Web/Bit.BlazorUI.Demo.Client.Web.csproj deleted file mode 100644 index eae23d0110..0000000000 --- a/src/BlazorUI/Demo/Client/Web/Bit.BlazorUI.Demo.Client.Web.csproj +++ /dev/null @@ -1,83 +0,0 @@ - - - - net8.0 - - true - false - - true - true - true - true - service-worker-assets.js - false - - false - - BeforeBuildTasks; - $(ResolveStaticWebAssetsInputsDependsOn) - - - - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - - - - - PreserveNewest - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/BlazorUI/Demo/Client/Web/Extensions/HttpRequestExtensions.cs b/src/BlazorUI/Demo/Client/Web/Extensions/HttpRequestExtensions.cs deleted file mode 100644 index ad186f2799..0000000000 --- a/src/BlazorUI/Demo/Client/Web/Extensions/HttpRequestExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Microsoft.Net.Http.Headers; - -namespace Microsoft.AspNetCore.Http; - -public static class HttpRequestExtensions -{ - /// - /// https://blog.elmah.io/how-to-get-base-url-in-asp-net-core/ - /// - public static string GetBaseUrl(this HttpRequest req) - { - var uriBuilder = new UriBuilder(req.Scheme, req.Host.Host, req.Host.Port ?? -1); - if (uriBuilder.Uri.IsDefaultPort) - { - uriBuilder.Port = -1; - } - - return uriBuilder.Uri.AbsoluteUri; - } - - public static bool ShouldRenderStaticMode(this HttpRequest request) - { - var agent = GetLoweredUserAgent(request); - - if (agent.Contains("google")) return true; - - if (agent.Contains("bing")) return true; - - if (agent.Contains("lighthouse")) return true; - - return false; - } - - private static string GetLoweredUserAgent(HttpRequest request) - { - var userAgent = request.Headers[HeaderNames.UserAgent].ToString(); - - if (string.IsNullOrEmpty(userAgent)) return string.Empty; - - return userAgent.ToLower(); - } -} diff --git a/src/BlazorUI/Demo/Client/Web/Pages/AppBupProgressBar.razor b/src/BlazorUI/Demo/Client/Web/Pages/AppBupProgressBar.razor deleted file mode 100644 index 2a173cdeb1..0000000000 --- a/src/BlazorUI/Demo/Client/Web/Pages/AppBupProgressBar.razor +++ /dev/null @@ -1,48 +0,0 @@ -@using Bit.Bup -@using Bit.BlazorUI - - - -@if (_showLoading) -{ -
- -
- - -
-} - -@code { - private bool _showLoading = true; - - protected override void OnAfterRender(bool firstRender) - { - base.OnAfterRender(firstRender); - if (firstRender is false) return; - - _showLoading = false; - StateHasChanged(); - } -} \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Web/Pages/_Host.cshtml b/src/BlazorUI/Demo/Client/Web/Pages/_Host.cshtml deleted file mode 100644 index bcebe94418..0000000000 --- a/src/BlazorUI/Demo/Client/Web/Pages/_Host.cshtml +++ /dev/null @@ -1,42 +0,0 @@ -@page "/" -@using Bit.BlazorUI.Demo.Client.Core; -@using Bit.BlazorUI.Demo.Shared.Infra; - -@namespace Bit.BlazorUI.Demo.Client.Web.Pages -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers - -@{ - Layout = "_Layout"; - var isBlazorServer = BlazorModeDetector.Current.IsBlazorServer(); - var isSpa = WebAppDeploymentTypeDetector.Current.IsSpa(); - var isPwa = WebAppDeploymentTypeDetector.Current.IsPwa(); - var isSpaPrerendered = WebAppDeploymentTypeDetector.Current.IsSpaPrerendered(); - var isPwaPrerendered = WebAppDeploymentTypeDetector.Current.IsPwaPrerendered(); - var isPrerenderedOnly = WebAppDeploymentTypeDetector.Current.IsPrerenderedOnly(); - - var noPrerender = Request.Query["no-prerender"].Count > 0; - - RenderMode renderMode = RenderMode.Static; - - if (isPrerenderedOnly is false) - { - if (isBlazorServer) - { - renderMode = isSpa || isPwa || noPrerender ? RenderMode.Server : RenderMode.ServerPrerendered; - } - else - { - renderMode = isSpa || isPwa || noPrerender ? RenderMode.WebAssembly : RenderMode.WebAssemblyPrerendered; - } - } - - if (renderMode is RenderMode.ServerPrerendered or RenderMode.WebAssemblyPrerendered) - { - if (Request.ShouldRenderStaticMode()) - { - renderMode = RenderMode.Static; - } - } -} - - diff --git a/src/BlazorUI/Demo/Client/Web/Pages/_Layout.cshtml b/src/BlazorUI/Demo/Client/Web/Pages/_Layout.cshtml deleted file mode 100644 index 73a094a066..0000000000 --- a/src/BlazorUI/Demo/Client/Web/Pages/_Layout.cshtml +++ /dev/null @@ -1,159 +0,0 @@ -@using Bit.BlazorUI.Demo.Shared.Infra -@using Microsoft.AspNetCore.Components.Web -@using RenderMode = Microsoft.AspNetCore.Mvc.Rendering.RenderMode - -@namespace Bit.BlazorUI.Demo.Client.Web.Pages -@inject IHttpContextAccessor ContextAccessor -@inject IConfiguration Configuration - -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers -@{ - var isElectron = BlazorModeDetector.Current.IsBlazorElectron(); - var isBlazorServer = BlazorModeDetector.Current.IsBlazorServer(); - var isSpa = WebAppDeploymentTypeDetector.Current.IsSpa(); - var isPwa = WebAppDeploymentTypeDetector.Current.IsPwa(); - var isSpaPrerendered = WebAppDeploymentTypeDetector.Current.IsSpaPrerendered(); - var isPwaPrerendered = WebAppDeploymentTypeDetector.Current.IsPwaPrerendered(); - var isPrerenderedOnly = WebAppDeploymentTypeDetector.Current.IsPrerenderedOnly(); - - var request = ContextAccessor?.HttpContext?.Request; - var noPrerender = (request?.Query["no-prerender"].Count ?? 0) > 0; - - RenderMode renderMode = RenderMode.Static; - if (isPrerenderedOnly is false) - { - if (isBlazorServer) - { - renderMode = isSpa || isPwa || noPrerender ? RenderMode.Server : RenderMode.ServerPrerendered; - } - else - { - renderMode = isSpa || isPwa || noPrerender ? RenderMode.WebAssembly : RenderMode.WebAssemblyPrerendered; - } - } - - if (renderMode is RenderMode.ServerPrerendered or RenderMode.WebAssemblyPrerendered) - { - if (request?.ShouldRenderStaticMode() is true) - { - renderMode = RenderMode.Static; - isPrerenderedOnly = true; - } - } -} - - - - - - - - - - - - - - - @if (isPwa || isPwaPrerendered) - { - - } - - - - - - - - - - - -
- @if (isSpa || isPwa || noPrerender) - { - - } - - - - - - - @RenderBody() - - -
- - @if (isPrerenderedOnly is false) - { - - - - - - @if (isBlazorServer) - { - - } - else - { - - @if (isPwa || isPwaPrerendered) - { - - - - @if (isPwaPrerendered) - { - - } - else - { - - - } - } - else if (isSpa || isSpaPrerendered) - { - - - @if (isSpaPrerendered) - { - - } - else - { - - - } - } - } - } - - @if ((isSpaPrerendered || isPwaPrerendered) && !noPrerender) - { - - } - - diff --git a/src/BlazorUI/Demo/Client/Web/Program.BlazorElectron.cs b/src/BlazorUI/Demo/Client/Web/Program.BlazorElectron.cs deleted file mode 100644 index 10be3413f0..0000000000 --- a/src/BlazorUI/Demo/Client/Web/Program.BlazorElectron.cs +++ /dev/null @@ -1,48 +0,0 @@ -#if BlazorElectron -using ElectronNET.API; -using ElectronNET.API.Entities; -#endif -namespace Bit.BlazorUI.Demo.Client.Web; - -public partial class Program -{ -#if BlazorElectron - public static WebApplication CreateHostBuilder(string[] args) - { - var builder = WebApplication.CreateBuilder(args); - builder.Configuration.AddClientConfigurations(); - - builder.WebHost.UseElectron(args); - builder.Services.AddElectron(); - - builder.WebHost.UseUrls("http://localhost:8001"); - - Startup.Services.Add(builder.Services, builder.Configuration); - - var app = builder.Build(); - - Startup.Middlewares.Use(app, builder.Environment); - - Task.Run(async () => - { - var window = await Electron.WindowManager.CreateWindowAsync(new BrowserWindowOptions - { - AutoHideMenuBar = true, - BackgroundColor = "#fff", - WebPreferences = new WebPreferences - { - NodeIntegration = false - } - }, "http://localhost:8001"); - - window.OnClosed += delegate - { - app.Services.GetRequiredService().StopApplication(); - Electron.App.Quit(); - }; - }); - - return app; - } -#endif -} diff --git a/src/BlazorUI/Demo/Client/Web/Program.BlazorServer.cs b/src/BlazorUI/Demo/Client/Web/Program.BlazorServer.cs deleted file mode 100644 index 167780e6ad..0000000000 --- a/src/BlazorUI/Demo/Client/Web/Program.BlazorServer.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Bit.BlazorUI.Demo.Client.Web; - -public partial class Program -{ -#if BlazorServer && !BlazorElectron - public static WebApplication CreateHostBuilder(string[] args) - { - var builder = WebApplication.CreateBuilder(args); - builder.Configuration.AddClientConfigurations(); - -#if DEBUG - if (OperatingSystem.IsWindows()) - { - // The following line (using the * in the URL), allows the emulators and mobile devices to access the app using the host IP address. - builder.WebHost.UseUrls("https://localhost:4001", "http://localhost:4000", "https://*:4001", "http://*:4000"); - } - else - { - builder.WebHost.UseUrls("https://localhost:4001", "http://localhost:4000"); - } -#endif - - Startup.Services.Add(builder.Services, builder.Configuration); - - var app = builder.Build(); - - Startup.Middlewares.Use(app, builder.Environment); - - return app; - } -#endif -} diff --git a/src/BlazorUI/Demo/Client/Web/Program.BlazorWebAssembly.cs b/src/BlazorUI/Demo/Client/Web/Program.BlazorWebAssembly.cs deleted file mode 100644 index eddfd42865..0000000000 --- a/src/BlazorUI/Demo/Client/Web/Program.BlazorWebAssembly.cs +++ /dev/null @@ -1,36 +0,0 @@ -#if BlazorWebAssembly -using Microsoft.AspNetCore.Components.WebAssembly.Hosting; -#endif - -namespace Bit.BlazorUI.Demo.Client.Web; - -public partial class Program -{ -#if BlazorWebAssembly - public static WebAssemblyHost CreateHostBuilder(string[] args) - { - var builder = WebAssemblyHostBuilder.CreateDefault(); - builder.Configuration.AddClientConfigurations(); - - var apiServerAddressConfig = builder.Configuration.GetApiServerAddress(); - - Uri.TryCreate(builder.Configuration.GetApiServerAddress(), UriKind.RelativeOrAbsolute, out var apiServerAddress); - - if (apiServerAddress.IsAbsoluteUri is false) - { - apiServerAddress = new Uri($"{builder.HostEnvironment.BaseAddress}{apiServerAddress}"); - } - - builder.Services.AddSingleton(sp => new HttpClient(sp.GetRequiredService()) { BaseAddress = apiServerAddress }); - builder.Services.AddScoped(); - - builder.Services.AddSharedServices(); - builder.Services.AddClientSharedServices(); - builder.Services.AddClientWebServices(); - - var host = builder.Build(); - - return host; - } -#endif -} diff --git a/src/BlazorUI/Demo/Client/Web/Program.cs b/src/BlazorUI/Demo/Client/Web/Program.cs deleted file mode 100644 index fdedd60ce4..0000000000 --- a/src/BlazorUI/Demo/Client/Web/Program.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Bit.BlazorUI.Demo.Client.Web; - -public partial class Program -{ - public static async Task Main(string[] args) - { -#if !BlazorWebAssembly && !BlazorServer - throw new InvalidOperationException("Please switch to either blazor web assembly or server as described in readme.md"); -#else - await CreateHostBuilder(args) - .RunAsync(); -#endif - } -} diff --git a/src/BlazorUI/Demo/Client/Web/Properties/launchSettings.json b/src/BlazorUI/Demo/Client/Web/Properties/launchSettings.json deleted file mode 100644 index 9f37cb6ba7..0000000000 --- a/src/BlazorUI/Demo/Client/Web/Properties/launchSettings.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "profiles": { - "Bit.BlazorUI.Demo.Client.Web": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:4001;http://localhost:4000" - }, - "Bit.BlazorUI.Demo.Client.Web.Electron": { - "commandName": "Executable", - "executablePath": "dotnet", - "commandLineArgs": "electronize start", - "workingDirectory": "." - } - } -} \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Web/Startup/Middlewares.cs b/src/BlazorUI/Demo/Client/Web/Startup/Middlewares.cs deleted file mode 100644 index 6f1554a9c9..0000000000 --- a/src/BlazorUI/Demo/Client/Web/Startup/Middlewares.cs +++ /dev/null @@ -1,30 +0,0 @@ -#if BlazorServer -namespace Bit.BlazorUI.Demo.Client.Web.Startup; - -public class Middlewares -{ - public static void Use(WebApplication app, IHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Error"); - } - - if (env.IsDevelopment() is false) - { - app.UseHttpsRedirection(); - app.UseResponseCompression(); - } - app.UseStaticFiles(); - - app.UseRouting(); - - app.MapBlazorHub(); - app.MapFallbackToPage("/_Host"); - } -} -#endif diff --git a/src/BlazorUI/Demo/Client/Web/Startup/Services.cs b/src/BlazorUI/Demo/Client/Web/Startup/Services.cs deleted file mode 100644 index 787189b395..0000000000 --- a/src/BlazorUI/Demo/Client/Web/Startup/Services.cs +++ /dev/null @@ -1,40 +0,0 @@ -#if BlazorServer -using System.IO.Compression; -using Microsoft.AspNetCore.ResponseCompression; - -namespace Bit.BlazorUI.Demo.Client.Web.Startup; - -public static class Services -{ - public static void Add(IServiceCollection services, IConfiguration configuration) - { - Uri.TryCreate(configuration.GetApiServerAddress(), UriKind.Absolute, out var apiServerAddress); - services.AddScoped(sp => - { - HttpClient httpClient = new(sp.GetRequiredService()) - { - BaseAddress = apiServerAddress - }; - - return httpClient; - }); - - services.AddHttpContextAccessor(); - services.AddRazorPages(); - services.AddServerSideBlazor(); - services.AddResponseCompression(opts => - { - opts.EnableForHttps = true; - opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/octet-stream" }).ToArray(); - opts.Providers.Add(); - opts.Providers.Add(); - }) - .Configure(opt => opt.Level = CompressionLevel.Fastest) - .Configure(opt => opt.Level = CompressionLevel.Fastest); - - services.AddSharedServices(); - services.AddClientSharedServices(); - services.AddClientWebServices(); - } -} -#endif diff --git a/src/BlazorUI/Demo/Client/Web/electron.manifest.json b/src/BlazorUI/Demo/Client/Web/electron.manifest.json deleted file mode 100644 index ba81214408..0000000000 --- a/src/BlazorUI/Demo/Client/Web/electron.manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "executable": "Bit.BlazorUI.Demo.Client.Web", - "splashscreen": { - "imageFile": "" - }, - "name": "BlazorUIDemo", - "author": "", - "singleInstance": true, - "environment": "Production", - "build": { - "appId": "com.Bit.BlazorUI.Demo.Client.Web.app", - "productName": "Bit.BlazorUI.Demo.Client.Web", - "copyright": "Copyright © 2023", - "buildVersion": "1.0.0", - "compression": "maximum", - "directories": { - "output": "../../../bin/Desktop" - }, - "extraResources": [ - { - "from": "./bin", - "to": "bin", - "filter": [ "**/*" ] - } - ], - "files": [ - { - "from": "./ElectronHostHook/node_modules", - "to": "ElectronHostHook/node_modules", - "filter": [ "**/*" ] - }, - "**/*" - ] - } -} \ No newline at end of file diff --git a/src/BlazorUI/Demo/Client/Web/wwwroot/service-worker.js b/src/BlazorUI/Demo/Client/Web/wwwroot/service-worker.js deleted file mode 100644 index b445666195..0000000000 --- a/src/BlazorUI/Demo/Client/Web/wwwroot/service-worker.js +++ /dev/null @@ -1,44 +0,0 @@ -// bit version: 8.2.0 -// https://github.com/bitfoundation/bitplatform/tree/develop/src/Bswup - -// Make sure to apply all changes you make here to the service-worker.published.js file too (if required). - -self.assetsExclude = [ - /bit\.blazorui\.fluent\.css$/, - /bit\.blazorui\.fluent-dark\.css$/, - /bit\.blazorui\.fluent-light\.css$/, -]; - -self.externalAssets = [ - { - "url": "/" - }, - { - "url": "https://www.googletagmanager.com/gtag/js?id=G-G1ET5L69QF" - }, - { - "url": "https://www.clarity.ms/s/0.7.10/clarity.js" - }, - { - "url": "https://www.clarity.ms/tag/ipec21ezsa" - } -]; - -self.serverHandledUrls = [ - /\/api\//, - /\/odata\//, - /\/jobs\//, - /\/core\//, - /\/signalr\//, - /\/healthchecks-ui/, - /\/healthz/, - /\/swagger/, - /\/api.fda.gov/ -]; - -self.isPassive = true; -self.defaultUrl = "/"; -self.caseInsensitiveUrl = true; -self.noPrerenderQuery = 'no-prerender=true'; - -self.importScripts('_content/Bit.Bswup/bit-bswup.sw.js'); diff --git a/src/BlazorUI/Demo/Directory.Build.props b/src/BlazorUI/Demo/Directory.Build.props index 45dd157273..87598d0144 100644 --- a/src/BlazorUI/Demo/Directory.Build.props +++ b/src/BlazorUI/Demo/Directory.Build.props @@ -1,66 +1,45 @@ - + - - BlazorServer - - - Spa - - - - - true - $(DefineConstants);BlazorElectron - Spa - BlazorServer - - $(DefineConstants);BlazorWebAssembly - $(DefineConstants);BlazorServer - $(DefineConstants);BlazorHybrid - $(DefineConstants);Spa - $(DefineConstants);Pwa - $(DefineConstants);SpaPrerendered - $(DefineConstants);PwaPrerendered - $(DefineConstants);PrerenderedOnly - $(DefineConstants);Android - $(DefineConstants);iOS - $(DefineConstants);Windows - $(DefineConstants);Mac - - 11.0 + 12.0 enable enable + true + $(NoWarn);CS1998;CS1591 + $(WarningsAsErrors);CS0114 - en - true - $(DefineConstants);MultilingualEnabled + en-US - 14.2 + false + $(DefineConstants);PwaEnabled + + 14.0 14.0 24.0 10.0.17763.0 10.0.17763.0 6.5 + $(DefineConstants);Android + $(DefineConstants);iOS + $(DefineConstants);Windows + $(DefineConstants);Mac - + - - - - - - - + + + + + diff --git a/src/BlazorUI/Demo/Server/Api/Controllers/AppControllerBase.cs b/src/BlazorUI/Demo/Server/Api/Controllers/AppControllerBase.cs deleted file mode 100644 index efe625235e..0000000000 --- a/src/BlazorUI/Demo/Server/Api/Controllers/AppControllerBase.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Bit.BlazorUI.Demo.Server.Api.Controllers; - -public partial class AppControllerBase : ControllerBase -{ - [AutoInject] protected AppSettings AppSettings = default!; - - [AutoInject] protected IStringLocalizer Localizer = default!; -} diff --git a/src/BlazorUI/Demo/Server/Api/Extensions/IApplicationBuilderExtensions.cs b/src/BlazorUI/Demo/Server/Api/Extensions/IApplicationBuilderExtensions.cs deleted file mode 100644 index e7fc6a7a17..0000000000 --- a/src/BlazorUI/Demo/Server/Api/Extensions/IApplicationBuilderExtensions.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Bit.BlazorUI.Demo.Server.Api.Middlewares; - -namespace Microsoft.AspNetCore.Builder; - -public static class IApplicationBuilderExtensions -{ - public static IApplicationBuilder UseHttpResponseExceptionHandler(this IApplicationBuilder builder) - { - return builder.UseMiddleware(); - } -} diff --git a/src/BlazorUI/Demo/Server/Api/Extensions/IServiceCollectionExtensions.cs b/src/BlazorUI/Demo/Server/Api/Extensions/IServiceCollectionExtensions.cs deleted file mode 100644 index bf930b6ca2..0000000000 --- a/src/BlazorUI/Demo/Server/Api/Extensions/IServiceCollectionExtensions.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Swashbuckle.AspNetCore.SwaggerGen; -using Bit.BlazorUI.Demo.Server.Api; - -namespace Microsoft.Extensions.DependencyInjection; - -public static class IServiceCollectionExtensions -{ - public static void AddSwaggerGen(this IServiceCollection services) - { - services.AddSwaggerGen(options => - { - options.OperationFilter(); - }); - } - - public static void AddHealthChecks(this IServiceCollection services, IWebHostEnvironment env, IConfiguration configuration) - { - var appSettings = configuration.GetSection(nameof(AppSettings)).Get(); - - var healthCheckSettings = appSettings.HealthCheckSettings; - - if (healthCheckSettings.EnableHealthChecks is false) - return; - - services.AddHealthChecksUI(setupSettings: setup => - { - setup.AddHealthCheckEndpoint("BitBlazorUIDemoHealthChecks", env.IsDevelopment() ? "https://localhost:5001/healthz" : "/healthz"); - }).AddInMemoryStorage(); - - var healthChecksBuilder = services.AddHealthChecks() - .AddProcessAllocatedMemoryHealthCheck(maximumMegabytesAllocated: 6 * 1024) - .AddDiskStorageHealthCheck(opt => - opt.AddDrive(Path.GetPathRoot(Directory.GetCurrentDirectory()), minimumFreeMegabytes: 5 * 1024)); - } -} diff --git a/src/BlazorUI/Demo/Server/Api/Middlewares/HttpResponseExceptionHandlerMiddleware.cs b/src/BlazorUI/Demo/Server/Api/Middlewares/HttpResponseExceptionHandlerMiddleware.cs deleted file mode 100644 index ec3fe8d4dc..0000000000 --- a/src/BlazorUI/Demo/Server/Api/Middlewares/HttpResponseExceptionHandlerMiddleware.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Net; -using System.Reflection; - -namespace Bit.BlazorUI.Demo.Server.Api.Middlewares; - -public class HttpResponseExceptionHandlerMiddleware -{ - private readonly RequestDelegate _next; - - public HttpResponseExceptionHandlerMiddleware(RequestDelegate next) - { - _next = next; - } - - public async Task Invoke(HttpContext context, IHostEnvironment webHostEnvironment) - { - // Using the Request-Id header, one can find the log for server-related exceptions - context.Response.Headers.Append("Request-ID", context.TraceIdentifier); - - try - { - await _next(context); - } - catch (Exception e) - { - var exception = UnWrapException(e); - var localizer = context.RequestServices.GetRequiredService>(); - var knownException = exception as KnownException; - - // The details of all of the exceptions are returned only in dev mode. in any other modes like production, only the details of the known exceptions are returned. - string key = knownException?.Key ?? nameof(UnknownException); - string message = knownException?.Message ?? (webHostEnvironment.IsDevelopment() ? exception.Message : localizer[nameof(UnknownException)]); - - var statusCode = (int)(exception is RestException restExp ? restExp.StatusCode : HttpStatusCode.InternalServerError); - - if (exception is KnownException && message == key) - { - message = localizer[message]; - } - - RestErrorInfo restExceptionPayload = new RestErrorInfo - { - Key = key, - Message = message, - ExceptionType = knownException?.GetType().FullName ?? typeof(UnknownException).FullName - }; - - if (exception is ResourceValidationException validationException) - { - restExceptionPayload.Payload = validationException.Payload; - } - - context.Response.StatusCode = statusCode; - - await context.Response.WriteAsJsonAsync(restExceptionPayload); - } - } - - private Exception UnWrapException(Exception exp) - { - return (exp is TargetInvocationException && exp.InnerException is not null) - ? exp.InnerException - : exp; - } -} diff --git a/src/BlazorUI/Demo/Server/Api/Program.cs b/src/BlazorUI/Demo/Server/Api/Program.cs deleted file mode 100644 index 050af97eef..0000000000 --- a/src/BlazorUI/Demo/Server/Api/Program.cs +++ /dev/null @@ -1,25 +0,0 @@ -var builder = WebApplication.CreateBuilder(args); - -#if BlazorWebAssembly -builder.Configuration.AddClientConfigurations(); -#endif - -#if DEBUG -if (OperatingSystem.IsWindows()) -{ -// The following line (using the * in the URL), allows the emulators and mobile devices to access the app using the host IP address. - builder.WebHost.UseUrls("https://localhost:5001", "http://localhost:5000", "https://*:5001", "http://*:5000"); -} -else -{ - builder.WebHost.UseUrls("https://localhost:5001", "http://localhost:5000"); -} -#endif - -Bit.BlazorUI.Demo.Server.Api.Startup.Services.Add(builder.Services, builder.Environment, builder.Configuration); - -var app = builder.Build(); - -Bit.BlazorUI.Demo.Server.Api.Startup.Middlewares.Use(app, builder.Environment, builder.Configuration); - -app.Run(); diff --git a/src/BlazorUI/Demo/Server/Api/Startup/Middlewares.cs b/src/BlazorUI/Demo/Server/Api/Startup/Middlewares.cs deleted file mode 100644 index 7201c2d9eb..0000000000 --- a/src/BlazorUI/Demo/Server/Api/Startup/Middlewares.cs +++ /dev/null @@ -1,84 +0,0 @@ -using HealthChecks.UI.Client; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.Net.Http.Headers; - -namespace Bit.BlazorUI.Demo.Server.Api.Startup; - -public class Middlewares -{ - public static void Use(WebApplication app, IHostEnvironment env, IConfiguration configuration) - { - app.UseForwardedHeaders(); - - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - -#if BlazorWebAssembly - if (env.IsDevelopment()) - { - app.UseWebAssemblyDebugging(); - } -#endif - } - -#if BlazorWebAssembly - app.UseBlazorFrameworkFiles(); -#endif - - if (env.IsDevelopment() is false) - { - app.UseHttpsRedirection(); - app.UseResponseCompression(); - } - - app.UseStaticFiles(new StaticFileOptions - { - OnPrepareResponse = ctx => - { - // https://bitplatform.dev/templates/cache-mechanism - ctx.Context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue() - { - MaxAge = TimeSpan.FromDays(7), - Public = true - }; - } - }); - - app.UseRouting(); - - // 0.0.0.0 is for the Blazor Hybrid mode (Android, iOS, Windows apps) - app.UseCors(options => options.WithOrigins("https://localhost:4001", "https://0.0.0.0", "app://0.0.0.0").AllowAnyHeader().AllowAnyMethod().AllowCredentials()); - - app.UseResponseCaching(); - - app.UseHttpResponseExceptionHandler(); - - app.UseSwagger(); - - app.UseSwaggerUI(options => - { - options.InjectJavascript("/swagger/swagger-utils.js"); - }); - - app.MapControllers(); - - var appSettings = configuration.GetSection(nameof(AppSettings)).Get(); - - var healthCheckSettings = appSettings.HealthCheckSettings; - - if (healthCheckSettings.EnableHealthChecks) - { - app.MapHealthChecks("/healthz", new HealthCheckOptions - { - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - app.MapHealthChecksUI(); - } - -#if BlazorWebAssembly - app.MapFallbackToPage("/_Host"); -#endif - } -} diff --git a/src/BlazorUI/Demo/Server/Api/Startup/Services.cs b/src/BlazorUI/Demo/Server/Api/Startup/Services.cs deleted file mode 100644 index bc392337f7..0000000000 --- a/src/BlazorUI/Demo/Server/Api/Startup/Services.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System.IO.Compression; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.HttpOverrides; -using Microsoft.AspNetCore.OData; -using Microsoft.AspNetCore.ResponseCompression; -using Microsoft.AspNetCore.Server.Kestrel.Core; -#if BlazorWebAssembly -using Bit.BlazorUI.Demo.Client.Core.Services; -using Microsoft.AspNetCore.Components; -#endif - -namespace Bit.BlazorUI.Demo.Server.Api.Startup; - -public static class Services -{ - public static void Add(IServiceCollection services, IWebHostEnvironment env, IConfiguration configuration) - { - // Services being registered here can get injected into controllers and services in Api project. - - var appSettings = configuration.GetSection(nameof(AppSettings)).Get(); - - services.AddSharedServices(); - -#if BlazorWebAssembly - services.AddClientSharedServices(); - services.AddClientWebServices(); - - // In the Pre-Rendering mode, the configured HttpClient will use the access_token provided by the cookie in the request, so the pre-rendered content would be fitting for the current user. - services.AddHttpClient("WebAssemblyPreRenderingHttpClient") - .ConfigurePrimaryHttpMessageHandler() - .ConfigureHttpClient((sp, httpClient) => - { - Uri.TryCreate(configuration.GetApiServerAddress(), UriKind.RelativeOrAbsolute, out var apiServerAddress); - if (apiServerAddress!.IsAbsoluteUri is false) - { - apiServerAddress = new Uri($"{sp.GetRequiredService().HttpContext!.Request.GetBaseUrl()}{apiServerAddress}"); - } - httpClient.BaseAddress = apiServerAddress; - }); - services.AddScoped(); - - services.AddScoped(sp => - { - IHttpClientFactory httpClientFactory = sp.GetRequiredService(); - return httpClientFactory.CreateClient("WebAssemblyPreRenderingHttpClient"); - // this is for pre rendering of blazor client/wasm - // for other usages of http client, for example calling 3rd party apis, either use services.AddHttpClient("NamedHttpClient") or services.AddHttpClient(); - }); - services.AddRazorPages(); -#endif - - services.AddCors(); - - services - .AddControllers() - .AddOData(options => options.EnableQueryFeatures()) - .AddDataAnnotationsLocalization(options => options.DataAnnotationLocalizerProvider = StringLocalizerProvider.ProvideLocalizer) - .ConfigureApiBehaviorOptions(options => - { - options.InvalidModelStateResponseFactory = context => - { - throw new ResourceValidationException(context.ModelState.Select(ms => (ms.Key, ms.Value!.Errors.Select(e => new LocalizedString(e.ErrorMessage, e.ErrorMessage)).ToArray())).ToArray()); - }; - }); - - services.Configure(options => - { - options.ForwardedHeaders = ForwardedHeaders.All; - options.ForwardedHostHeaderName = "X-Host"; - }); - - services.AddResponseCaching(); - - services.AddHttpContextAccessor(); - - services.AddResponseCompression(opts => - { - opts.EnableForHttps = true; - opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/octet-stream" }).ToArray(); - opts.Providers.Add(); - opts.Providers.Add(); - }) - .Configure(opt => opt.Level = CompressionLevel.Fastest) - .Configure(opt => opt.Level = CompressionLevel.Fastest); - - services.Configure(configuration.GetSection(nameof(AppSettings))); - - services.AddScoped(sp => sp.GetRequiredService>().Value); - - services.AddEndpointsApiExplorer(); - - services.AddSwaggerGen(); - - services.AddHealthChecks(env, configuration); - - services.Configure(options => - { - options.Limits.MaxRequestBodySize = int.MaxValue; // if don't set default value is: 30 MB - }); - - services.Configure(options => - { - options.ValueLengthLimit = int.MaxValue; - options.MultipartBodyLengthLimit = int.MaxValue; // if don't set default value is: 128 MB - options.MultipartHeadersLengthLimit = int.MaxValue; - }); - } -} diff --git a/src/BlazorUI/Demo/Shared/Attributes/AutoInjectAttribute.cs b/src/BlazorUI/Demo/Shared/Attributes/AutoInjectAttribute.cs deleted file mode 100644 index 3d0d2d298d..0000000000 --- a/src/BlazorUI/Demo/Shared/Attributes/AutoInjectAttribute.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Microsoft.Extensions.DependencyInjection; - -/// -/// This attribute can be applied on either fields or properties to generate the rest of the required codes using Bit.SourceGenerators. -/// The Bit.SourceGenerators for this attribute generates an appropriate property with the [Inject] attribute for Blazor components and constructor injection for other classes. -/// -[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, Inherited = false, AllowMultiple = false)] -public sealed class AutoInjectAttribute : Attribute -{ -} diff --git a/src/BlazorUI/Demo/Shared/Attributes/DtoResourceTypeAttribute.cs b/src/BlazorUI/Demo/Shared/Attributes/DtoResourceTypeAttribute.cs deleted file mode 100644 index 134c8b2896..0000000000 --- a/src/BlazorUI/Demo/Shared/Attributes/DtoResourceTypeAttribute.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Bit.BlazorUI.Demo.Shared.Attributes; - -/// -/// Gets or sets the resource type to use for error message & localizations lookups. -/// -public class DtoResourceTypeAttribute : Attribute -{ - public Type ResourceType { get; } - - public DtoResourceTypeAttribute(Type resourceType) - { - ResourceType = resourceType ?? throw new ArgumentNullException(nameof(resourceType)); - } -} diff --git a/src/BlazorUI/Demo/Shared/Extensions/IServiceCollectionExtensions.cs b/src/BlazorUI/Demo/Shared/Extensions/IServiceCollectionExtensions.cs deleted file mode 100644 index 3036d580fb..0000000000 --- a/src/BlazorUI/Demo/Shared/Extensions/IServiceCollectionExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Bit.BlazorUI.Demo.Shared.Services; - -namespace Microsoft.Extensions.DependencyInjection; - -public static class IServiceCollectionExtensions -{ - public static void AddSharedServices(this IServiceCollection services) - { - // Services being registered here can get injected everywhere (Api, Web, Android, iOS, Windows, macOS and Linux) - - services.AddLocalization(); - - services.AddSingleton(); - } -} diff --git a/src/BlazorUI/Demo/Shared/Infra/BlazorMode.cs b/src/BlazorUI/Demo/Shared/Infra/BlazorMode.cs deleted file mode 100644 index 914dca9f06..0000000000 --- a/src/BlazorUI/Demo/Shared/Infra/BlazorMode.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Bit.BlazorUI.Demo.Shared.Infra; - -public enum BlazorMode -{ - BlazorServer = 0, - BlazorWebAssembly = 1, - BlazorHybrid = 2, -#if BlazorElectron - BlazorElectron = 0, -#else - BlazorElectron = 3 -#endif -} diff --git a/src/BlazorUI/Demo/Shared/Infra/BlazorModeDetector.cs b/src/BlazorUI/Demo/Shared/Infra/BlazorModeDetector.cs deleted file mode 100644 index 66a4a84088..0000000000 --- a/src/BlazorUI/Demo/Shared/Infra/BlazorModeDetector.cs +++ /dev/null @@ -1,45 +0,0 @@ -namespace Bit.BlazorUI.Demo.Shared.Infra; - -/// -/// https://bitplatform.dev/templates/hosting-models -/// -public class BlazorModeDetector -{ - public static BlazorModeDetector Current { get; set; } = new BlazorModeDetector(); - - public virtual bool IsBlazorServer() - { - return Mode == BlazorMode.BlazorServer; - } - - public virtual bool IsBlazorWebAssembly() - { - return Mode == BlazorMode.BlazorWebAssembly; - } - - public virtual bool IsBlazorHybrid() - { - return Mode == BlazorMode.BlazorHybrid; - } - - public virtual bool IsBlazorElectron() - { - return Mode == BlazorMode.BlazorElectron; - } - - public virtual BlazorMode Mode - { - get - { -#if BlazorElectron - return BlazorMode.BlazorElectron; -#elif BlazorWebAssembly - return BlazorMode.BlazorWebAssembly; -#elif BlazorHybrid - return BlazorMode.BlazorHybrid; -#else - return BlazorMode.BlazorServer; -#endif - } - } -} diff --git a/src/BlazorUI/Demo/Shared/Infra/BuildConfigurationMode.cs b/src/BlazorUI/Demo/Shared/Infra/BuildConfigurationMode.cs deleted file mode 100644 index c51590f14b..0000000000 --- a/src/BlazorUI/Demo/Shared/Infra/BuildConfigurationMode.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Bit.BlazorUI.Demo.Shared.Infra; - -public enum BuildConfigurationMode -{ - Debug, - Release -} diff --git a/src/BlazorUI/Demo/Shared/Infra/BuildConfigurationModeDetector.cs b/src/BlazorUI/Demo/Shared/Infra/BuildConfigurationModeDetector.cs deleted file mode 100644 index 837fd09ab5..0000000000 --- a/src/BlazorUI/Demo/Shared/Infra/BuildConfigurationModeDetector.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Bit.BlazorUI.Demo.Shared.Infra; - -public class BuildConfigurationModeDetector -{ - public static BuildConfigurationModeDetector Current { get; set; } = new BuildConfigurationModeDetector(); - - public virtual bool IsDebug() - { - return Mode == BuildConfigurationMode.Debug; - } - - - public virtual bool Release() - { - return Mode == BuildConfigurationMode.Release; - } - - - public virtual BuildConfigurationMode Mode - { - get - { -#if DEBUG - return BuildConfigurationMode.Debug; -#else - return BuildConfigurationMode.Release; -#endif - - } - } -} diff --git a/src/BlazorUI/Demo/Shared/Infra/CultureInfoManager.cs b/src/BlazorUI/Demo/Shared/Infra/CultureInfoManager.cs deleted file mode 100644 index 8295667b4e..0000000000 --- a/src/BlazorUI/Demo/Shared/Infra/CultureInfoManager.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System.Reflection; - -namespace Bit.BlazorUI.Demo.Shared.Infra; -public class CultureInfoManager -{ - public static (string name, string code) DefaultCulture { get; } = ("English", "en-US"); - - public static (string name, string code)[] SupportedCultures { get; } = new (string name, string code)[] - { - ("English US", "en-US"), - // ("فارسی", "fa-IR"), // To add more languages, you've to provide resx files. You might also put some efforts to change your app flow direction based on CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft - }; - - public static CultureInfo CreateCultureInfo(string cultureInfoId) - { - var cultureInfo = OperatingSystem.IsBrowser() ? CultureInfo.CreateSpecificCulture(cultureInfoId) : new CultureInfo(cultureInfoId); - - if (cultureInfoId == "fa-IR") - { - CustomizeCultureInfoForFaCulture(cultureInfo); - } - - return cultureInfo; - } - - public static void SetCurrentCulture(string? cultureInfoCookie) - { - var currentCulture = GetCurrentCulture(cultureInfoCookie); - - var cultureInfo = CreateCultureInfo(currentCulture); - - CultureInfo.CurrentCulture = CultureInfo.CurrentUICulture = CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = cultureInfo; - } - - public static string GetCurrentCulture(string? preferredCultureCookie) - { - string culture = CultureInfo.CurrentUICulture.Name; - if (preferredCultureCookie is not null) - { - culture = preferredCultureCookie[(preferredCultureCookie.IndexOf("|uic=") + 5)..]; - } - if (SupportedCultures.Any(sc => sc.code == culture) is false) - { - culture = DefaultCulture.code; - } - return culture; - } - - /// - /// This is an example to demonstrate the way you can customize application culture - /// - public static CultureInfo CustomizeCultureInfoForFaCulture(CultureInfo cultureInfo) - { - cultureInfo.DateTimeFormat.MonthNames = new[] - { - "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند", "" - }; - - cultureInfo.DateTimeFormat.AbbreviatedMonthNames = new[] - { - "فرور", "ارد", "خرد", "تیر", "مرد", "شهر", "مهر", "آبا", "آذر", "دی", "بهم", "اسف", "" - }; - - cultureInfo.DateTimeFormat.MonthGenitiveNames = cultureInfo.DateTimeFormat.MonthNames; - cultureInfo.DateTimeFormat.AbbreviatedMonthGenitiveNames = cultureInfo.DateTimeFormat.AbbreviatedMonthNames; - cultureInfo.DateTimeFormat.DayNames = new[] - { - "یکشنبه", "دوشنبه", "ﺳﻪشنبه", "چهارشنبه", "پنجشنبه", "جمعه", "شنبه" - }; - - cultureInfo.DateTimeFormat.AbbreviatedDayNames = new[] - { - "ی", "د", "س", "چ", "پ", "ج", "ش" - }; - - cultureInfo.DateTimeFormat.ShortestDayNames = new[] - { - "ی", "د", "س", "چ", "پ", "ج", "ش" - }; - - cultureInfo.DateTimeFormat.AMDesignator = "ق.ظ"; - cultureInfo.DateTimeFormat.PMDesignator = "ب.ظ"; - cultureInfo.DateTimeFormat.ShortDatePattern = "yyyy/MM/dd"; - cultureInfo.DateTimeFormat.FirstDayOfWeek = DayOfWeek.Saturday; - - var cultureData = _cultureDataField.GetValue(cultureInfo.TextInfo); - - _iReadingLayoutField.SetValue(cultureData, 1 /*rtl*/); // this affects cultureInfo.TextInfo.IsRightToLeft - - if (cultureInfo.DateTimeFormat.Calendar is not PersianCalendar) - { - cultureInfo.DateTimeFormat.Calendar = new PersianCalendar(); - } - - return cultureInfo; - } - - private static readonly FieldInfo _cultureDataField = typeof(TextInfo).GetField("_cultureData", BindingFlags.NonPublic | BindingFlags.Instance)!; - - private static readonly FieldInfo _iReadingLayoutField = Type.GetType("System.Globalization.CultureData, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e")!.GetField("_iReadingLayout", BindingFlags.NonPublic | BindingFlags.Instance)!; -} diff --git a/src/BlazorUI/Demo/Shared/Infra/WebAppDeploymentType.cs b/src/BlazorUI/Demo/Shared/Infra/WebAppDeploymentType.cs deleted file mode 100644 index bceb8bcfab..0000000000 --- a/src/BlazorUI/Demo/Shared/Infra/WebAppDeploymentType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Bit.BlazorUI.Demo.Shared.Infra; - -public enum WebAppDeploymentType -{ - Spa, - Pwa, - SpaPrerendered, - PwaPrerendered, - PrerenderedOnly, -} diff --git a/src/BlazorUI/Demo/Shared/Infra/WebAppDeploymentTypeDetector.cs b/src/BlazorUI/Demo/Shared/Infra/WebAppDeploymentTypeDetector.cs deleted file mode 100644 index 44612984e6..0000000000 --- a/src/BlazorUI/Demo/Shared/Infra/WebAppDeploymentTypeDetector.cs +++ /dev/null @@ -1,52 +0,0 @@ -namespace Bit.BlazorUI.Demo.Shared.Infra; - -/// -/// https://bitplatform.dev/templates/hosting-models -/// -public class WebAppDeploymentTypeDetector -{ - public static WebAppDeploymentTypeDetector Current { get; set; } = new WebAppDeploymentTypeDetector(); - - public virtual bool IsPrerenderedOnly() - { - return Mode == WebAppDeploymentType.PrerenderedOnly; - } - - public virtual bool IsSpa() - { - return Mode == WebAppDeploymentType.Spa; - } - - public virtual bool IsPwa() - { - return Mode == WebAppDeploymentType.Pwa; - } - - public virtual bool IsSpaPrerendered() - { - return Mode == WebAppDeploymentType.SpaPrerendered; - } - - public virtual bool IsPwaPrerendered() - { - return Mode == WebAppDeploymentType.PwaPrerendered; - } - - public virtual WebAppDeploymentType Mode - { - get - { -#if PrerenderedOnly - return WebAppDeploymentType.PrerenderedOnly; -#elif Spa - return WebAppDeploymentType.Spa; -#elif Pwa - return WebAppDeploymentType.Pwa; -#elif SpaPrerendered - return WebAppDeploymentType.SpaPrerendered; -#elif PwaPrerendered - return WebAppDeploymentType.PwaPrerendered; -#endif - } - } -} diff --git a/src/BlazorUI/Demo/Shared/Resources/AppStrings.Designer.cs b/src/BlazorUI/Demo/Shared/Resources/AppStrings.Designer.cs deleted file mode 100644 index 63693bd4d3..0000000000 --- a/src/BlazorUI/Demo/Shared/Resources/AppStrings.Designer.cs +++ /dev/null @@ -1,1594 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Bit.BlazorUI.Demo.Shared.Resources { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class AppStrings { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal AppStrings() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Bit.BlazorUI.Demo.Shared.Resources.AppStrings", typeof(AppStrings).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Active. - /// - public static string Active { - get { - return ResourceManager.GetString("Active", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add. - /// - public static string Add { - get { - return ResourceManager.GetString("Add", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to All. - /// - public static string All { - get { - return ResourceManager.GetString("All", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Alphabetical. - /// - public static string Alphabetical { - get { - return ResourceManager.GetString("Alphabetical", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Already have an account?. - /// - public static string AlreadyHaveAccountMessage { - get { - return ResourceManager.GetString("AlreadyHaveAccountMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The argument '{0}' cannot be null, empty or contain only whitespace.. - /// - public static string ArgumentIsNullOrWhitespace { - get { - return ResourceManager.GetString("ArgumentIsNullOrWhitespace", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The associated metadata type for type '{0}' contains the following unknown properties or fields: {1}. Please make sure that the names of these members match the names of the properties on the main type.. - /// - public static string AssociatedMetadataTypeTypeDescriptor_MetadataTypeContainsUnknownProperties { - get { - return ResourceManager.GetString("AssociatedMetadataTypeTypeDescriptor_MetadataTypeContainsUnknownProperties", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The type '{0}' does not contain a public property named '{1}'.. - /// - public static string AttributeStore_Unknown_Property { - get { - return ResourceManager.GetString("AttributeStore_Unknown_Property", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid request. - /// - public static string BadRequestException { - get { - return ResourceManager.GetString("BadRequestException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Birthdate. - /// - public static string BirthDate { - get { - return ResourceManager.GetString("BirthDate", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel. - /// - public static string Cancel { - get { - return ResourceManager.GetString("Cancel", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Check your Spam/Junk, if you could not find it in the Inbox.. - /// - public static string CheckSpamMailMessage { - get { - return ResourceManager.GetString("CheckSpamMailMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The property {0}.{1} could not be found.. - /// - public static string Common_PropertyNotFound { - get { - return ResourceManager.GetString("Common_PropertyNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Could not find a property named {0}.. - /// - public static string CompareAttribute_UnknownProperty { - get { - return ResourceManager.GetString("CompareAttribute_UnknownProperty", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to '{0}' and '{1}' do not match.. - /// - public static string CompareAttribute_ValidationError { - get { - return ResourceManager.GetString("CompareAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Completed. - /// - public static string Completed { - get { - return ResourceManager.GetString("Completed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Optimistic concurrency failure, object has been modified.. - /// - public static string ConcurrencyFailure { - get { - return ResourceManager.GetString("ConcurrencyFailure", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to We have sent a confirmation link to your email address. - ///Please confirm your email by clicking on the link.. - /// - public static string ConfirmEmailMessage { - get { - return ResourceManager.GetString("ConfirmEmailMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Confirm Your Email Address. - /// - public static string ConfirmEmailTitle { - get { - return ResourceManager.GetString("ConfirmEmailTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Confirm New Password. - /// - public static string ConfirmNewPassword { - get { - return ResourceManager.GetString("ConfirmNewPassword", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Request could not be processed because of conflict in the request. - /// - public static string ConflicException { - get { - return ResourceManager.GetString("ConflicException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} field is not a valid credit card number.. - /// - public static string CreditCardAttribute_Invalid { - get { - return ResourceManager.GetString("CreditCardAttribute_Invalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The CustomValidationAttribute method '{0}' in type '{1}' must return System.ComponentModel.DataAnnotations.ValidationResult. Use System.ComponentModel.DataAnnotations.ValidationResult.Success to represent success.. - /// - public static string CustomValidationAttribute_Method_Must_Return_ValidationResult { - get { - return ResourceManager.GetString("CustomValidationAttribute_Method_Must_Return_ValidationResult", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The CustomValidationAttribute method '{0}' does not exist in type '{1}' or is not public and static.. - /// - public static string CustomValidationAttribute_Method_Not_Found { - get { - return ResourceManager.GetString("CustomValidationAttribute_Method_Not_Found", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The CustomValidationAttribute.Method was not specified.. - /// - public static string CustomValidationAttribute_Method_Required { - get { - return ResourceManager.GetString("CustomValidationAttribute_Method_Required", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The CustomValidationAttribute method '{0}' in type '{1}' must match the expected signature: public static ValidationResult {0}(object value, ValidationContext context). The value can be strongly typed. The ValidationContext parameter is optional.. - /// - public static string CustomValidationAttribute_Method_Signature { - get { - return ResourceManager.GetString("CustomValidationAttribute_Method_Signature", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Could not convert the value of type '{0}' to '{1}' as expected by method {2}.{3}.. - /// - public static string CustomValidationAttribute_Type_Conversion_Failed { - get { - return ResourceManager.GetString("CustomValidationAttribute_Type_Conversion_Failed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The custom validation type '{0}' must be public.. - /// - public static string CustomValidationAttribute_Type_Must_Be_Public { - get { - return ResourceManager.GetString("CustomValidationAttribute_Type_Must_Be_Public", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} is not valid.. - /// - public static string CustomValidationAttribute_ValidationError { - get { - return ResourceManager.GetString("CustomValidationAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The CustomValidationAttribute.ValidatorType was not specified.. - /// - public static string CustomValidationAttribute_ValidatorType_Required { - get { - return ResourceManager.GetString("CustomValidationAttribute_ValidatorType_Required", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The custom DataType string cannot be null or empty.. - /// - public static string DataTypeAttribute_EmptyDataTypeString { - get { - return ResourceManager.GetString("DataTypeAttribute_EmptyDataTypeString", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Date. - /// - public static string Date { - get { - return ResourceManager.GetString("Date", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} property has not been set. Use the {1} method to get the value.. - /// - public static string DisplayAttribute_PropertyNotSet { - get { - return ResourceManager.GetString("DisplayAttribute_PropertyNotSet", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Don’t have an account?. - /// - public static string DontHaveAccountMessage { - get { - return ResourceManager.GetString("DontHaveAccountMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email '{0}' is already taken.. - /// - public static string DuplicateEmail { - get { - return ResourceManager.GetString("DuplicateEmail", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Role name '{0}' is already taken.. - /// - public static string DuplicateRoleName { - get { - return ResourceManager.GetString("DuplicateRoleName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Username '{0}' is already taken.. - /// - public static string DuplicateUserName { - get { - return ResourceManager.GetString("DuplicateUserName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Edit. - /// - public static string Edit { - get { - return ResourceManager.GetString("Edit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Edit profile. - /// - public static string EditProfileTitle { - get { - return ResourceManager.GetString("EditProfileTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email. - /// - public static string Email { - get { - return ResourceManager.GetString("Email", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} field is not a valid e-mail address.. - /// - public static string EmailAddressAttribute_ValidationError { - get { - return ResourceManager.GetString("EmailAddressAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your email is already confirmed.. - /// - public static string EmailAlreadyConfirmed { - get { - return ResourceManager.GetString("EmailAlreadyConfirmed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email Confirmation Failed!. - /// - public static string EmailConfirmationFailedMessage { - get { - return ResourceManager.GetString("EmailConfirmationFailedMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email Confirmation. - /// - public static string EmailConfirmationTitle { - get { - return ResourceManager.GetString("EmailConfirmationTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email Confirmed Successfully!. - /// - public static string EmailConfirmedSuccessfullyMessage { - get { - return ResourceManager.GetString("EmailConfirmedSuccessfullyMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email '{0}' is not confirmed.. - /// - public static string EmailNotConfirmed { - get { - return ResourceManager.GetString("EmailNotConfirmed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The type provided for EnumDataTypeAttribute cannot be null.. - /// - public static string EnumDataTypeAttribute_TypeCannotBeNull { - get { - return ResourceManager.GetString("EnumDataTypeAttribute_TypeCannotBeNull", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The type '{0}' needs to represent an enumeration type.. - /// - public static string EnumDataTypeAttribute_TypeNeedsToBeAnEnum { - get { - return ResourceManager.GetString("EnumDataTypeAttribute_TypeNeedsToBeAnEnum", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error. - /// - public static string Error { - get { - return ResourceManager.GetString("Error", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} field only accepts files with the following extensions: {1}. - /// - public static string FileExtensionsAttribute_Invalid { - get { - return ResourceManager.GetString("FileExtensionsAttribute_Invalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to An error occurred while removing file. - /// - public static string FileRemoveFailed { - get { - return ResourceManager.GetString("FileRemoveFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to An error occurred while uploading file. - /// - public static string FileUploadFailed { - get { - return ResourceManager.GetString("FileUploadFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Access to the requested resource is forbidden. - /// - public static string ForbiddenException { - get { - return ResourceManager.GetString("ForbiddenException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Please enter the email address you have been signed up with so we can send a reset password link to your email address.. - /// - public static string ForgetPasswordMessage { - get { - return ResourceManager.GetString("ForgetPasswordMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Forget password. - /// - public static string ForgetPasswordTitle { - get { - return ResourceManager.GetString("ForgetPasswordTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Forgot password?. - /// - public static string ForgotPasswordLink { - get { - return ResourceManager.GetString("ForgotPasswordLink", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Full Name. - /// - public static string FullName { - get { - return ResourceManager.GetString("FullName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Gender. - /// - public static string Gender { - get { - return ResourceManager.GetString("Gender", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Custom. - /// - public static string GenderCustom { - get { - return ResourceManager.GetString("GenderCustom", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Female. - /// - public static string GenderFemale { - get { - return ResourceManager.GetString("GenderFemale", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Male. - /// - public static string GenderMale { - get { - return ResourceManager.GetString("GenderMale", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to GitHub Repo. - /// - public static string GitHubRepo { - get { - return ResourceManager.GetString("GitHubRepo", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Go to today. - /// - public static string GoToToday { - get { - return ResourceManager.GetString("GoToToday", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Home. - /// - public static string Home { - get { - return ResourceManager.GetString("Home", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Create your multi-mode (WASM, Server, Hybrid, pre-rendering) Blazor app easily in the shortest time ever!. - /// - public static string HomeMessage { - get { - return ResourceManager.GetString("HomeMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Bit.BlazorUI.Demo Home. - /// - public static string HomeTitle { - get { - return ResourceManager.GetString("HomeTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Looks like the confirmation link either is invalid or has expired.. - /// - public static string InvalidConfirmationLinkMessage { - get { - return ResourceManager.GetString("InvalidConfirmationLinkMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email '{0}' is invalid.. - /// - public static string InvalidEmail { - get { - return ResourceManager.GetString("InvalidEmail", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Role name '{0}' is invalid.. - /// - public static string InvalidRoleName { - get { - return ResourceManager.GetString("InvalidRoleName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid token.. - /// - public static string InvalidToken { - get { - return ResourceManager.GetString("InvalidToken", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Username '{0}' is invalid, can only contain letters or digits.. - /// - public static string InvalidUserName { - get { - return ResourceManager.GetString("InvalidUserName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Is accept privacy policy?. - /// - public static string IsAcceptPrivacy { - get { - return ResourceManager.GetString("IsAcceptPrivacy", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Known error. - /// - public static string KnownException { - get { - return ResourceManager.GetString("KnownException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field of type {0} must be a string, array or ICollection type.. - /// - public static string LengthAttribute_InvalidValueType { - get { - return ResourceManager.GetString("LengthAttribute_InvalidValueType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cannot retrieve property '{0}' because localization failed. Type '{1}' is not public or does not contain a public static string property with the name '{2}'.. - /// - public static string LocalizableString_LocalizationFailed { - get { - return ResourceManager.GetString("LocalizableString_LocalizationFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to A user with this login already exists.. - /// - public static string LoginAlreadyAssociated { - get { - return ResourceManager.GetString("LoginAlreadyAssociated", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MaxLengthAttribute must have a Length value that is greater than zero. Use MaxLength() without parameters to indicate that the string or array can have the maximum allowable length.. - /// - public static string MaxLengthAttribute_InvalidMaxLength { - get { - return ResourceManager.GetString("MaxLengthAttribute_InvalidMaxLength", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field {0} must be a string or array type with a maximum length of '{1}'.. - /// - public static string MaxLengthAttribute_ValidationError { - get { - return ResourceManager.GetString("MaxLengthAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MetadataClassType cannot be null.. - /// - public static string MetadataTypeAttribute_TypeCannotBeNull { - get { - return ResourceManager.GetString("MetadataTypeAttribute_TypeCannotBeNull", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MinLengthAttribute must have a Length value that is zero or greater.. - /// - public static string MinLengthAttribute_InvalidMinLength { - get { - return ResourceManager.GetString("MinLengthAttribute_InvalidMinLength", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field {0} must be a string or array type with a minimum length of '{1}'.. - /// - public static string MinLengthAttribute_ValidationError { - get { - return ResourceManager.GetString("MinLengthAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to New Password. - /// - public static string NewPassword { - get { - return ResourceManager.GetString("NewPassword", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No todos yet. - /// - public static string NoTodos { - get { - return ResourceManager.GetString("NoTodos", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Haven’t you received the confirmation email?. - /// - public static string NotReceivedConfirmationEmailMessage { - get { - return ResourceManager.GetString("NotReceivedConfirmationEmailMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Haven’t you received the confirmation email?. - /// - public static string NotReceivedConfirmationEmailMessage1 { - get { - return ResourceManager.GetString("NotReceivedConfirmationEmailMessage1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to OR. - /// - public static string Or { - get { - return ResourceManager.GetString("Or", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Password. - /// - public static string Password { - get { - return ResourceManager.GetString("Password", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your password changed successfully.. - /// - public static string PasswordChangedSuccessfullyMessage { - get { - return ResourceManager.GetString("PasswordChangedSuccessfullyMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Incorrect password.. - /// - public static string PasswordMismatch { - get { - return ResourceManager.GetString("PasswordMismatch", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Passwords must have at least one digit ('0'-'9').. - /// - public static string PasswordRequiresDigit { - get { - return ResourceManager.GetString("PasswordRequiresDigit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Passwords must have at least one lowercase ('a'-'z').. - /// - public static string PasswordRequiresLower { - get { - return ResourceManager.GetString("PasswordRequiresLower", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Passwords must have at least one non alphanumeric character.. - /// - public static string PasswordRequiresNonAlphanumeric { - get { - return ResourceManager.GetString("PasswordRequiresNonAlphanumeric", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Passwords must use at least {0} different characters.. - /// - public static string PasswordRequiresUniqueChars { - get { - return ResourceManager.GetString("PasswordRequiresUniqueChars", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Passwords must have at least one uppercase ('A'-'Z').. - /// - public static string PasswordRequiresUpper { - get { - return ResourceManager.GetString("PasswordRequiresUpper", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} field is not a valid phone number.. - /// - public static string PhoneAttribute_Invalid { - get { - return ResourceManager.GetString("PhoneAttribute_Invalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Phone number. - /// - public static string PhoneNumber { - get { - return ResourceManager.GetString("PhoneNumber", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Privacy. - /// - public static string Privacy { - get { - return ResourceManager.GetString("Privacy", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to I agree to the . - /// - public static string PrivacyPolicyAgreementMessage { - get { - return ResourceManager.GetString("PrivacyPolicyAgreementMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use this page to detail your site's privacy policy.. - /// - public static string PrivacyPolicyPageMessage { - get { - return ResourceManager.GetString("PrivacyPolicyPageMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use this section to detail your site's privacy policy.. - /// - public static string PrivacyPolicySectionMessage { - get { - return ResourceManager.GetString("PrivacyPolicySectionMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Privacy Policy. - /// - public static string PrivacyPolicyTitle { - get { - return ResourceManager.GetString("PrivacyPolicyTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Profile Image. - /// - public static string ProfileImage { - get { - return ResourceManager.GetString("ProfileImage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Profile updated successfully.. - /// - public static string ProfileUpdatedSuccessfullyMessage { - get { - return ResourceManager.GetString("ProfileUpdatedSuccessfullyMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The type {0} must implement {1}.. - /// - public static string RangeAttribute_ArbitraryTypeNotIComparable { - get { - return ResourceManager.GetString("RangeAttribute_ArbitraryTypeNotIComparable", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The maximum value '{0}' must be greater than or equal to the minimum value '{1}'.. - /// - public static string RangeAttribute_MinGreaterThanMax { - get { - return ResourceManager.GetString("RangeAttribute_MinGreaterThanMax", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The minimum and maximum values must be set.. - /// - public static string RangeAttribute_Must_Set_Min_And_Max { - get { - return ResourceManager.GetString("RangeAttribute_Must_Set_Min_And_Max", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The OperandType must be set when strings are used for minimum and maximum values.. - /// - public static string RangeAttribute_Must_Set_Operand_Type { - get { - return ResourceManager.GetString("RangeAttribute_Must_Set_Operand_Type", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field {0} must be between {1} and {2}.. - /// - public static string RangeAttribute_ValidationError { - get { - return ResourceManager.GetString("RangeAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Recovery code redemption failed.. - /// - public static string RecoveryCodeRedemptionFailed { - get { - return ResourceManager.GetString("RecoveryCodeRedemptionFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field {0} must match the regular expression '{1}'.. - /// - public static string RegexAttribute_ValidationError { - get { - return ResourceManager.GetString("RegexAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The pattern must be set to a valid regular expression.. - /// - public static string RegularExpressionAttribute_Empty_Pattern { - get { - return ResourceManager.GetString("RegularExpressionAttribute_Empty_Pattern", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Remove. - /// - public static string Remove { - get { - return ResourceManager.GetString("Remove", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} field is required.. - /// - public static string RequiredAttribute_ValidationError { - get { - return ResourceManager.GetString("RequiredAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The confirmation link has been re-sent to your email address.. - /// - public static string ResendConfirmationLinkMessage { - get { - return ResourceManager.GetString("ResendConfirmationLinkMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Resend email. - /// - public static string ResendEmail { - get { - return ResourceManager.GetString("ResendEmail", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Reset password. - /// - public static string ResetPassword { - get { - return ResourceManager.GetString("ResetPassword", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The reset password link has been sent to your email address.. - /// - public static string ResetPasswordLinkSentMessage { - get { - return ResourceManager.GetString("ResetPasswordLinkSentMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Reset password. - /// - public static string ResetPasswordTitle { - get { - return ResourceManager.GetString("ResetPasswordTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Resource not found. - /// - public static string ResourceNotFoundException { - get { - return ResourceManager.GetString("ResourceNotFoundException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Request data is not valid. - /// - public static string ResourceValidationException { - get { - return ResourceManager.GetString("ResourceValidationException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to An error occurred while communicating with server. - /// - public static string RestException { - get { - return ResourceManager.GetString("RestException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Role {0} does not exist.. - /// - public static string RoleNotFound { - get { - return ResourceManager.GetString("RoleNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Save. - /// - public static string Save { - get { - return ResourceManager.GetString("Save", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Select your birth date. - /// - public static string SelectBirthDate { - get { - return ResourceManager.GetString("SelectBirthDate", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sign in. - /// - public static string SignIn { - get { - return ResourceManager.GetString("SignIn", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sign in. - /// - public static string SignInTitle { - get { - return ResourceManager.GetString("SignInTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sign out. - /// - public static string SignOut { - get { - return ResourceManager.GetString("SignOut", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Are you sure you want to Sign out?. - /// - public static string SignOutPrompt { - get { - return ResourceManager.GetString("SignOutPrompt", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sign up. - /// - public static string SignUp { - get { - return ResourceManager.GetString("SignUp", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sign up. - /// - public static string SingUpTitle { - get { - return ResourceManager.GetString("SingUpTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sort by. - /// - public static string SortBy { - get { - return ResourceManager.GetString("SortBy", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The maximum length must be a nonnegative integer.. - /// - public static string StringLengthAttribute_InvalidMaxLength { - get { - return ResourceManager.GetString("StringLengthAttribute_InvalidMaxLength", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field {0} must be a string with a maximum length of {1}.. - /// - public static string StringLengthAttribute_ValidationError { - get { - return ResourceManager.GetString("StringLengthAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.. - /// - public static string StringLengthAttribute_ValidationErrorIncludingMinimum { - get { - return ResourceManager.GetString("StringLengthAttribute_ValidationErrorIncludingMinimum", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Submit. - /// - public static string Submit { - get { - return ResourceManager.GetString("Submit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Terms. - /// - public static string TermsTitle { - get { - return ResourceManager.GetString("TermsTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Title. - /// - public static string Title { - get { - return ResourceManager.GetString("Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add a todo. - /// - public static string TodoAddPlaceholder { - get { - return ResourceManager.GetString("TodoAddPlaceholder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to To Do item could not be found. - /// - public static string ToDoItemCouldNotBeFound { - get { - return ResourceManager.GetString("ToDoItemCouldNotBeFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Search some todo.... - /// - public static string TodoSearchPlaceholder { - get { - return ResourceManager.GetString("TodoSearchPlaceholder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Todo. - /// - public static string TodoTitle { - get { - return ResourceManager.GetString("TodoTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Too many requests. - /// - public static string TooManyRequestsExceptions { - get { - return ResourceManager.GetString("TooManyRequestsExceptions", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The key parameter at position {0} with value '{1}' is not a string. Every key control parameter must be a string.. - /// - public static string UIHintImplementation_ControlParameterKeyIsNotAString { - get { - return ResourceManager.GetString("UIHintImplementation_ControlParameterKeyIsNotAString", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The key parameter at position {0} is null. Every key control parameter must be a string.. - /// - public static string UIHintImplementation_ControlParameterKeyIsNull { - get { - return ResourceManager.GetString("UIHintImplementation_ControlParameterKeyIsNull", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The key parameter at position {0} with value '{1}' occurs more than once.. - /// - public static string UIHintImplementation_ControlParameterKeyOccursMoreThanOnce { - get { - return ResourceManager.GetString("UIHintImplementation_ControlParameterKeyOccursMoreThanOnce", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The number of control parameters must be even.. - /// - public static string UIHintImplementation_NeedEvenNumberOfControlParameters { - get { - return ResourceManager.GetString("UIHintImplementation_NeedEvenNumberOfControlParameters", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your request lacks valid authentication credentials. - /// - public static string UnauthorizedException { - get { - return ResourceManager.GetString("UnauthorizedException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unknown error has occurred. - /// - public static string UnknownException { - get { - return ResourceManager.GetString("UnknownException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The record was modified by another user after you got the original data. the operation was canceled.. - /// - public static string UpdateConcurrencyException { - get { - return ResourceManager.GetString("UpdateConcurrencyException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Upload a new profile image. - /// - public static string UploadNewProfileImage { - get { - return ResourceManager.GetString("UploadNewProfileImage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} field is not a valid fully-qualified http, https, or ftp URL.. - /// - public static string UrlAttribute_Invalid { - get { - return ResourceManager.GetString("UrlAttribute_Invalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User already has a password set.. - /// - public static string UserAlreadyHasPassword { - get { - return ResourceManager.GetString("UserAlreadyHasPassword", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User already in role '{0}'.. - /// - public static string UserAlreadyInRole { - get { - return ResourceManager.GetString("UserAlreadyInRole", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User image could not be found. - /// - public static string UserImageCouldNotBeFound { - get { - return ResourceManager.GetString("UserImageCouldNotBeFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User is locked out. Try again in {0}. - /// - public static string UserLockedOut { - get { - return ResourceManager.GetString("UserLockedOut", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Username. - /// - public static string UserName { - get { - return ResourceManager.GetString("UserName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User {0} does not exist.. - /// - public static string UserNameNotFound { - get { - return ResourceManager.GetString("UserNameNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User is not in role '{0}'.. - /// - public static string UserNotInRole { - get { - return ResourceManager.GetString("UserNotInRole", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Either ErrorMessageString or ErrorMessageResourceName must be set, but not both.. - /// - public static string ValidationAttribute_Cannot_Set_ErrorMessage_And_Resource { - get { - return ResourceManager.GetString("ValidationAttribute_Cannot_Set_ErrorMessage_And_Resource", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to IsValid(object value) has not been implemented by this class. The preferred entry point is GetValidationResult() and classes should override IsValid(object value, ValidationContext context).. - /// - public static string ValidationAttribute_IsValid_NotImplemented { - get { - return ResourceManager.GetString("ValidationAttribute_IsValid_NotImplemented", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Both ErrorMessageResourceType and ErrorMessageResourceName need to be set on this attribute.. - /// - public static string ValidationAttribute_NeedBothResourceTypeAndResourceName { - get { - return ResourceManager.GetString("ValidationAttribute_NeedBothResourceTypeAndResourceName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The property '{0}' on resource type '{1}' is not a string type.. - /// - public static string ValidationAttribute_ResourcePropertyNotStringType { - get { - return ResourceManager.GetString("ValidationAttribute_ResourcePropertyNotStringType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The resource type '{0}' does not have an accessible static property named '{1}'.. - /// - public static string ValidationAttribute_ResourceTypeDoesNotHaveProperty { - get { - return ResourceManager.GetString("ValidationAttribute_ResourceTypeDoesNotHaveProperty", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field {0} is invalid.. - /// - public static string ValidationAttribute_ValidationError { - get { - return ResourceManager.GetString("ValidationAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The instance provided must match the ObjectInstance on the ValidationContext supplied.. - /// - public static string Validator_InstanceMustMatchValidationContextInstance { - get { - return ResourceManager.GetString("Validator_InstanceMustMatchValidationContextInstance", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The value for property '{0}' must be of type '{1}'.. - /// - public static string Validator_Property_Value_Wrong_Type { - get { - return ResourceManager.GetString("Validator_Property_Value_Wrong_Type", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You have already requested the confirmation email. Try again in {0}. - /// - public static string WaitForConfirmationEmailResendDelay { - get { - return ResourceManager.GetString("WaitForConfirmationEmailResendDelay", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You have already requested the reset password email. Try again in {0}. - /// - public static string WaitForResetPasswordEmailResendDelay { - get { - return ResourceManager.GetString("WaitForResetPasswordEmailResendDelay", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You must agree to our privacy policy.. - /// - public static string YouHaveToAcceptPrivacyPolicy { - get { - return ResourceManager.GetString("YouHaveToAcceptPrivacyPolicy", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You must be signed in to continue.. - /// - public static string YouNeedToSignIn { - get { - return ResourceManager.GetString("YouNeedToSignIn", resourceCulture); - } - } - } -} diff --git a/src/BlazorUI/Demo/Shared/Resources/AppStrings.resx b/src/BlazorUI/Demo/Shared/Resources/AppStrings.resx deleted file mode 100644 index a870e453cd..0000000000 --- a/src/BlazorUI/Demo/Shared/Resources/AppStrings.resx +++ /dev/null @@ -1,654 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Invalid request - - - Request could not be processed because of conflict in the request - - - An error occurred while removing file - - - An error occurred while uploading file - - - Access to the requested resource is forbidden - - - Request data is not valid - - - An error occurred while communicating with server - - - To Do item could not be found - - - Your request lacks valid authentication credentials - - - Unknown error has occurred - - - User image could not be found - - - Optimistic concurrency failure, object has been modified. - Error when optimistic concurrency fails - - - Email '{0}' is already taken. - Error for duplicate emails - - - Role name '{0}' is already taken. - Error for duplicate roles - - - Username '{0}' is already taken. - Error for duplicate user names - - - Email '{0}' is invalid. - Invalid email - - - Role name '{0}' is invalid. - Error for invalid role names - - - Invalid token. - Error when a token is not recognized - - - Username '{0}' is invalid, can only contain letters or digits. - User names can only contain letters or digits - - - A user with this login already exists. - Error when a login already linked - - - Incorrect password. - Error when a password doesn't match - - - Passwords must have at least one digit ('0'-'9'). - Error when passwords do not have a digit - - - Passwords must have at least one lowercase ('a'-'z'). - Error when passwords do not have a lowercase letter - - - Passwords must have at least one non alphanumeric character. - Error when password does not have enough non alphanumeric characters - - - Passwords must have at least one uppercase ('A'-'Z'). - Error when passwords do not have an uppercase letter - - - The field {0} must be a string or array type with a minimum length of '{1}'. - - - Role {0} does not exist. - Error when a role does not exist - - - Recovery code redemption failed. - Error when a recovery code is not redeemed. - - - User already has a password set. - Error when AddPasswordAsync called when a user already has a password - - - User already in role '{0}'. - Error when a user is already in a role - - - User is locked out. Try again in {0} - Error when a user is locked out - - - User {0} does not exist. - Error when a user does not exist - - - User is not in role '{0}'. - Error when a user is not in the role - - - Passwords must use at least {0} different characters. - Error message for passwords that are based on similar characters - - - Email '{0}' is not confirmed. - Error when a email is not confirmed by the confirmation link - - - You have already requested the confirmation email. Try again in {0} - - - You have already requested the reset password email. Try again in {0} - - - Your email is already confirmed. - - - The record was modified by another user after you got the original data. the operation was canceled. - - - Known error - - - Resource not found - - - Too many requests - - - Error - - - Active - - - Add - - - All - - - Alphabetical - - - Already have an account? - - - Cancel - - - Check your Spam/Junk, if you could not find it in the Inbox. - - - Completed - - - We have sent a confirmation link to your email address. -Please confirm your email by clicking on the link. - - - Confirm Your Email Address - - - Confirm New Password - - - Date - - - Don’t have an account? - - - Edit - - - Edit profile - - - Email - - - Email Confirmation Failed! - - - Email Confirmation - - - Email Confirmed Successfully! - - - Please enter the email address you have been signed up with so we can send a reset password link to your email address. - - - Forget password - - - Forgot password? - - - Full Name - - - Custom - - - Female - - - Male - - - GitHub Repo - - - Looks like the confirmation link either is invalid or has expired. - - - New Password - - - No todos yet - - - Haven’t you received the confirmation email? - - - Haven’t you received the confirmation email? - - - OR - - - Password - - - Your password changed successfully. - - - I agree to the - - - Use this page to detail your site's privacy policy. - - - Use this section to detail your site's privacy policy. - - - Privacy Policy - - - Profile updated successfully. - - - Remove - - - The confirmation link has been re-sent to your email address. - - - Resend email - - - Reset password - - - The reset password link has been sent to your email address. - - - Reset password - - - Save - - - Select your birth date - - - Sign in - - - Sign in - - - Sign out - - - Sign up - - - Sign up - - - Sort by - - - Submit - - - Add a todo - - - Search some todo... - - - Create your multi-mode (WASM, Server, Hybrid, pre-rendering) Blazor app easily in the shortest time ever! - - - Bit.BlazorUI.Demo Home - - - Todo - - - Upload a new profile image - - - The argument '{0}' cannot be null, empty or contain only whitespace. - - - The associated metadata type for type '{0}' contains the following unknown properties or fields: {1}. Please make sure that the names of these members match the names of the properties on the main type. - - - The type '{0}' does not contain a public property named '{1}'. - - - The property {0}.{1} could not be found. - - - '{0}' and '{1}' do not match. - - - Could not find a property named {0}. - - - The {0} field is not a valid credit card number. - - - The CustomValidationAttribute method '{0}' in type '{1}' must return System.ComponentModel.DataAnnotations.ValidationResult. Use System.ComponentModel.DataAnnotations.ValidationResult.Success to represent success. - - - The CustomValidationAttribute method '{0}' does not exist in type '{1}' or is not public and static. - - - The CustomValidationAttribute.Method was not specified. - - - The CustomValidationAttribute method '{0}' in type '{1}' must match the expected signature: public static ValidationResult {0}(object value, ValidationContext context). The value can be strongly typed. The ValidationContext parameter is optional. - - - Could not convert the value of type '{0}' to '{1}' as expected by method {2}.{3}. - - - The custom validation type '{0}' must be public. - - - {0} is not valid. - - - The CustomValidationAttribute.ValidatorType was not specified. - - - The custom DataType string cannot be null or empty. - - - The {0} property has not been set. Use the {1} method to get the value. - - - The {0} field is not a valid e-mail address. - - - The type provided for EnumDataTypeAttribute cannot be null. - - - The type '{0}' needs to represent an enumeration type. - - - The {0} field only accepts files with the following extensions: {1} - - - The field of type {0} must be a string, array or ICollection type. - - - Cannot retrieve property '{0}' because localization failed. Type '{1}' is not public or does not contain a public static string property with the name '{2}'. - - - MaxLengthAttribute must have a Length value that is greater than zero. Use MaxLength() without parameters to indicate that the string or array can have the maximum allowable length. - - - The field {0} must be a string or array type with a maximum length of '{1}'. - - - MetadataClassType cannot be null. - - - MinLengthAttribute must have a Length value that is zero or greater. - - - The {0} field is not a valid phone number. - - - The type {0} must implement {1}. - - - The maximum value '{0}' must be greater than or equal to the minimum value '{1}'. - - - The minimum and maximum values must be set. - - - The OperandType must be set when strings are used for minimum and maximum values. - - - The field {0} must be between {1} and {2}. - - - The field {0} must match the regular expression '{1}'. - - - The pattern must be set to a valid regular expression. - - - The {0} field is required. - - - The maximum length must be a nonnegative integer. - - - The field {0} must be a string with a maximum length of {1}. - - - The field {0} must be a string with a minimum length of {2} and a maximum length of {1}. - - - The key parameter at position {0} with value '{1}' is not a string. Every key control parameter must be a string. - - - The key parameter at position {0} is null. Every key control parameter must be a string. - - - The key parameter at position {0} with value '{1}' occurs more than once. - - - The number of control parameters must be even. - - - The {0} field is not a valid fully-qualified http, https, or ftp URL. - - - Either ErrorMessageString or ErrorMessageResourceName must be set, but not both. - - - IsValid(object value) has not been implemented by this class. The preferred entry point is GetValidationResult() and classes should override IsValid(object value, ValidationContext context). - - - Both ErrorMessageResourceType and ErrorMessageResourceName need to be set on this attribute. - - - The property '{0}' on resource type '{1}' is not a string type. - - - The resource type '{0}' does not have an accessible static property named '{1}'. - - - The field {0} is invalid. - - - The instance provided must match the ObjectInstance on the ValidationContext supplied. - - - The value for property '{0}' must be of type '{1}'. - - - Is accept privacy policy? - - - Phone number - - - Username - - - You must agree to our privacy policy. - - - Go to today - - - Gender - - - Privacy - - - Are you sure you want to Sign out? - - - Birthdate - - - Home - - - Profile Image - - - Title - - - You must be signed in to continue. - - - Terms - - \ No newline at end of file diff --git a/src/BlazorUI/Demo/Shared/Resources/StringLocalizerProvider.cs b/src/BlazorUI/Demo/Shared/Resources/StringLocalizerProvider.cs deleted file mode 100644 index 017a8166aa..0000000000 --- a/src/BlazorUI/Demo/Shared/Resources/StringLocalizerProvider.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Reflection; - -namespace Bit.BlazorUI.Demo.Shared.Resources; - -public static class StringLocalizerProvider -{ - public static IStringLocalizer ProvideLocalizer(Type dtoType, IStringLocalizerFactory factory) - { - return factory.Create(dtoType.GetCustomAttribute()?.ResourceType ?? typeof(AppStrings)); - } -} diff --git a/src/BlazorUI/Demo/Shared/Services/Contracts/IDateTimeProvider.cs b/src/BlazorUI/Demo/Shared/Services/Contracts/IDateTimeProvider.cs deleted file mode 100644 index 924ebb35c8..0000000000 --- a/src/BlazorUI/Demo/Shared/Services/Contracts/IDateTimeProvider.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Bit.BlazorUI.Demo.Shared.Services.Contracts; - -public interface IDateTimeProvider -{ - DateTimeOffset GetCurrentDateTime(); -} diff --git a/src/BlazorUI/Demo/Shared/Services/DateTimeProvider.cs b/src/BlazorUI/Demo/Shared/Services/DateTimeProvider.cs deleted file mode 100644 index 9483acf62c..0000000000 --- a/src/BlazorUI/Demo/Shared/Services/DateTimeProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Bit.BlazorUI.Demo.Shared.Services; - -public class DateTimeProvider : IDateTimeProvider -{ - public DateTimeOffset GetCurrentDateTime() - { - return DateTimeOffset.UtcNow; - } -} diff --git a/src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.js b/src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.js index f594644b54..7b8cbae33d 100644 --- a/src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.js +++ b/src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.js @@ -1,4 +1,4 @@ -// bit version: 8.2.0 +// bit version: 8.3.0 self.assetsExclude = [/\.scp\.css$/, /weather\.json$/]; self.caseInsensitiveUrl = true; diff --git a/src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.published.js b/src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.published.js index c095861e92..941ffb1fe5 100644 --- a/src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.published.js +++ b/src/Bswup/Bit.Bswup.Demo/wwwroot/service-worker.published.js @@ -1,4 +1,4 @@ -// bit version: 8.2.0 +// bit version: 8.3.0 self.assetsExclude = [/\.scp\.css$/, /weather\.json$/]; self.caseInsensitiveUrl = true; diff --git a/src/Bswup/Bit.Bswup.NewDemo/Bit.Bswup.NewDemo.Client/wwwroot/service-worker.js b/src/Bswup/Bit.Bswup.NewDemo/Bit.Bswup.NewDemo.Client/wwwroot/service-worker.js index 44eaac6249..f9b7c100db 100644 --- a/src/Bswup/Bit.Bswup.NewDemo/Bit.Bswup.NewDemo.Client/wwwroot/service-worker.js +++ b/src/Bswup/Bit.Bswup.NewDemo/Bit.Bswup.NewDemo.Client/wwwroot/service-worker.js @@ -1,4 +1,4 @@ -// bit version: 8.2.0 +// bit version: 8.3.0 // In development, always fetch from the network and do not enable offline support. // This is because caching would make development more difficult (changes would not diff --git a/src/Bswup/Bit.Bswup.NewDemo/Bit.Bswup.NewDemo.Client/wwwroot/service-worker.published.js b/src/Bswup/Bit.Bswup.NewDemo/Bit.Bswup.NewDemo.Client/wwwroot/service-worker.published.js index f5151e0981..1be5d14a02 100644 --- a/src/Bswup/Bit.Bswup.NewDemo/Bit.Bswup.NewDemo.Client/wwwroot/service-worker.published.js +++ b/src/Bswup/Bit.Bswup.NewDemo/Bit.Bswup.NewDemo.Client/wwwroot/service-worker.published.js @@ -1,4 +1,4 @@ -// bit version: 8.2.0 +// bit version: 8.3.0 self.assetsInclude = []; self.assetsExclude = [ diff --git a/src/Bswup/Bit.Bswup/Scripts/bit-bswup.progress.ts b/src/Bswup/Bit.Bswup/Scripts/bit-bswup.progress.ts index 4cddd530d3..207cca88a4 100644 --- a/src/Bswup/Bit.Bswup/Scripts/bit-bswup.progress.ts +++ b/src/Bswup/Bit.Bswup/Scripts/bit-bswup.progress.ts @@ -1,4 +1,4 @@ -window['bit-bswup.progress version'] = '8.2.0'; +window['bit-bswup.progress version'] = '8.3.0'; ; (function () { (window as any).startBswupProgress = (autoReload: boolean, diff --git a/src/Bswup/Bit.Bswup/Scripts/bit-bswup.sw.ts b/src/Bswup/Bit.Bswup/Scripts/bit-bswup.sw.ts index b92aa5b392..529860c0e4 100644 --- a/src/Bswup/Bit.Bswup/Scripts/bit-bswup.sw.ts +++ b/src/Bswup/Bit.Bswup/Scripts/bit-bswup.sw.ts @@ -1,4 +1,4 @@ -self['bit-bswup.sw version'] = '8.2.0'; +self['bit-bswup.sw version'] = '8.3.0'; interface Window { clients: any diff --git a/src/Bswup/Bit.Bswup/Scripts/bit-bswup.ts b/src/Bswup/Bit.Bswup/Scripts/bit-bswup.ts index c295b82b44..098f8c3780 100644 --- a/src/Bswup/Bit.Bswup/Scripts/bit-bswup.ts +++ b/src/Bswup/Bit.Bswup/Scripts/bit-bswup.ts @@ -1,4 +1,4 @@ -window['bit-bswup version'] = '8.2.0'; +window['bit-bswup version'] = '8.3.0'; declare const Blazor: any; diff --git a/src/Bswup/FullDemo/Client/wwwroot/service-worker.js b/src/Bswup/FullDemo/Client/wwwroot/service-worker.js index 3fc6dd6e74..b446b61a61 100644 --- a/src/Bswup/FullDemo/Client/wwwroot/service-worker.js +++ b/src/Bswup/FullDemo/Client/wwwroot/service-worker.js @@ -1,4 +1,4 @@ -// bit version: 8.2.0 +// bit version: 8.3.0 // In development, always fetch from the network and do not enable offline support. // This is because caching would make development more difficult (changes would not diff --git a/src/Bswup/FullDemo/Client/wwwroot/service-worker.published.js b/src/Bswup/FullDemo/Client/wwwroot/service-worker.published.js index a4ef6c25c8..235acee014 100644 --- a/src/Bswup/FullDemo/Client/wwwroot/service-worker.published.js +++ b/src/Bswup/FullDemo/Client/wwwroot/service-worker.published.js @@ -1,4 +1,4 @@ -// bit version: 8.2.0 +// bit version: 8.3.0 self.assetsInclude = []; self.assetsExclude = [/\.scp\.css$/, /weather\.json$/]; diff --git a/src/Bup/Bit.Bup/Scripts/bit-bup.progress.ts b/src/Bup/Bit.Bup/Scripts/bit-bup.progress.ts index a52727b87f..367154e846 100644 --- a/src/Bup/Bit.Bup/Scripts/bit-bup.progress.ts +++ b/src/Bup/Bit.Bup/Scripts/bit-bup.progress.ts @@ -1,4 +1,4 @@ -window['bit-bup.progress version'] = '8.2.0'; +window['bit-bup.progress version'] = '8.3.0'; ; (function () { (window as any).startBupProgress = (showLogs: boolean, showAssets: boolean, appContainerSelector: string, hideApp: boolean, autoHide: boolean) => { diff --git a/src/Bup/Bit.Bup/Scripts/bit-bup.ts b/src/Bup/Bit.Bup/Scripts/bit-bup.ts index 95d79b5261..293fad037e 100644 --- a/src/Bup/Bit.Bup/Scripts/bit-bup.ts +++ b/src/Bup/Bit.Bup/Scripts/bit-bup.ts @@ -1,4 +1,4 @@ -window['bit-bup version'] = '8.2.0'; +window['bit-bup version'] = '8.3.0'; declare const Blazor: any; diff --git a/src/Butil/Bit.Butil.Demo/Pages/ElementPage.razor b/src/Butil/Bit.Butil.Demo/Pages/ElementPage.razor new file mode 100644 index 0000000000..bcaf25ad3a --- /dev/null +++ b/src/Butil/Bit.Butil.Demo/Pages/ElementPage.razor @@ -0,0 +1,37 @@ +@page "/element" +@inject Bit.Butil.Console console +@inject Bit.Butil.Element element + +Element Samples + +

Element

+ +
+@@inject Bit.Butil.Element element
+
+@@code {
+    ...
+    var rect = await element.GetBoundingClientRect();
+    ...
+}
+
+ +
+
+
+ +

Open the DevTools

+
+
Element
+
+ + +@code { + private ElementReference elementRef = default!; + + private async Task GetBoundingClientRect() + { + var rect = await element.GetBoundingClientRect(elementRef); + await console.Log("BoundingClientRect:", rect); + } +} \ No newline at end of file diff --git a/src/Butil/Bit.Butil.Demo/Pages/HistoryPage.razor b/src/Butil/Bit.Butil.Demo/Pages/HistoryPage.razor new file mode 100644 index 0000000000..8b38650515 --- /dev/null +++ b/src/Butil/Bit.Butil.Demo/Pages/HistoryPage.razor @@ -0,0 +1,63 @@ +@page "/history" +@implements IDisposable +@inject Bit.Butil.Console console +@inject Bit.Butil.History history + +History Samples + +

History

+ +
+@@inject Bit.Butil.History history
+
+@@code {
+    ...
+    await history.GoBack();
+    ...
+}
+
+ +
+
+
+ +

Open the DevTools

+
+ +
+ +
+ + +@code { + protected override async Task OnInitializedAsync() + { + // await history.PushState(new { Name = "Saleh1" }, "#1"); + // await history.PushState(new { Name = "Saleh2" }, "#2"); + + await history.AddPopState(o => _ = console.Log("Popped state:", o)); + + await base.OnInitializedAsync(); + } + + private async Task GetLength() + { + var length = await history.GetLength(); + await console.Log("History length", length); + } + + private async Task GoBack() + { + await history.GoBack(); + } + + private async Task GoForward() + { + await history.GoForward(); + } + + public void Dispose() + { + history.Dispose(); + } +} \ No newline at end of file diff --git a/src/Butil/Bit.Butil.Demo/Pages/KeyboardPage.razor b/src/Butil/Bit.Butil.Demo/Pages/KeyboardPage.razor index 3f82174da2..ef4f84428a 100644 --- a/src/Butil/Bit.Butil.Demo/Pages/KeyboardPage.razor +++ b/src/Butil/Bit.Butil.Demo/Pages/KeyboardPage.razor @@ -8,22 +8,22 @@

Keyboard

-@inject Bit.Butil.Keyboard keyboard
+@@inject Bit.Butil.Keyboard keyboard
 
 @@code {
     ...
-    await keyboard.Add("F10", args => { ... }, , ButilModifiers.Alt | ButilModifiers.Ctrl);
+    await keyboard.Add(ButilKeyCodes.F10, args => { ... }, , ButilModifiers.Alt | ButilModifiers.Ctrl);
     ...
 }
 
-

Open the DevTools and start pressing F9 and Ctrl+Alt+F10

+

Open the DevTools console and start pressing F5 or Ctrl+Alt+F10

@code { protected override async Task OnInitializedAsync() { - await keyboard.Add("F5", () => _ = console.Log("F5 is pressed!")); - await keyboard.Add("F10", () => _ = console.Log("Ctrl+Alt+F10 is pressed!"), ButilModifiers.Alt | ButilModifiers.Ctrl); + await keyboard.Add(ButilKeyCodes.F5, () => _ = console.Log("F5 is pressed!")); + await keyboard.Add(ButilKeyCodes.F10, () => _ = console.Log("Ctrl+Alt+F10 is pressed!"), ButilModifiers.Alt | ButilModifiers.Ctrl); base.OnInitialized(); } diff --git a/src/Butil/Bit.Butil.Demo/Pages/NavigatorPage.razor b/src/Butil/Bit.Butil.Demo/Pages/NavigatorPage.razor new file mode 100644 index 0000000000..50311b8f9b --- /dev/null +++ b/src/Butil/Bit.Butil.Demo/Pages/NavigatorPage.razor @@ -0,0 +1,33 @@ +@page "/navigator" +@inject Bit.Butil.Console console +@inject Bit.Butil.Navigator navigator + +Navigator Samples + +

Navigator

+ +
+@@inject Bit.Butil.Navigator navigator
+
+@@code {
+    ...
+    var userAgent = await navigator.GetUserAgent();
+    ...
+}
+
+ +
+
+
+ +

Open the DevTools

+
+ + + +@code { + private async Task GetUserAgent() + { + _ = console.Log("User agent:", await navigator.GetUserAgent()); + } +} \ No newline at end of file diff --git a/src/Butil/Bit.Butil.Demo/Shared/Header.razor b/src/Butil/Bit.Butil.Demo/Shared/Header.razor index eb6846be8c..b7af35f3bc 100644 --- a/src/Butil/Bit.Butil.Demo/Shared/Header.razor +++ b/src/Butil/Bit.Butil.Demo/Shared/Header.razor @@ -1,8 +1,11 @@ 
\ No newline at end of file diff --git a/src/Butil/Bit.Butil/BitButil.cs b/src/Butil/Bit.Butil/BitButil.cs index c308947249..1a48be358d 100644 --- a/src/Butil/Bit.Butil/BitButil.cs +++ b/src/Butil/Bit.Butil/BitButil.cs @@ -10,6 +10,9 @@ public static IServiceCollection AddBitButilServices(this IServiceCollection ser services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); return services; } diff --git a/src/Butil/Bit.Butil/Internals/History/HistoryListenersManager.cs b/src/Butil/Bit.Butil/Internals/History/HistoryListenersManager.cs new file mode 100644 index 0000000000..b336a25518 --- /dev/null +++ b/src/Butil/Bit.Butil/Internals/History/HistoryListenersManager.cs @@ -0,0 +1,53 @@ +using System; +using System.Linq; +using System.Collections.Concurrent; +using Microsoft.JSInterop; + +namespace Bit.Butil; + +public static class HistoryListenersManager +{ + internal const string InvokeMethodName = "InvokeHistoryPopState"; + + private static readonly ConcurrentDictionary Listeners = []; + + internal static Guid AddListener(Action action) + { + var id = Guid.NewGuid(); + + Listeners.TryAdd(id, new Listener { Action = action }); + + return id; + } + + internal static Guid[] RemoveListener(Action action) + { + var listenersToRemove = Listeners.Where(l => l.Value.Action == action).ToArray(); + + return listenersToRemove.Select(l => + { + Listeners.TryRemove(l.Key, out _); + return l.Key; + }).ToArray(); + } + + internal static void RemoveListeners(Guid[] ids) + { + foreach (var id in ids) + { + Listeners.TryRemove(id, out _); + } + } + + [JSInvokable(InvokeMethodName)] + public static void Invoke(Guid id, object state) + { + Listeners.TryGetValue(id, out Listener? listener); + listener?.Action.Invoke(state); + } + + private class Listener + { + public Action Action { get; set; } = default!; + } +} diff --git a/src/Butil/Bit.Butil/Internals/JsInterops/ConsoleJsInterop.cs b/src/Butil/Bit.Butil/Internals/JsInterops/ConsoleJsInterop.cs index 1518adb9d3..dce73f8663 100644 --- a/src/Butil/Bit.Butil/Internals/JsInterops/ConsoleJsInterop.cs +++ b/src/Butil/Bit.Butil/Internals/JsInterops/ConsoleJsInterop.cs @@ -5,118 +5,72 @@ namespace Bit.Butil; internal static class ConsoleJsInterop { - internal static async Task Assert(this IJSRuntime js, bool? condition, params object?[]? args) - { - await js.InvokeVoidAsync("BitButil.console.assert", [condition, ..args]); - } - - internal static async Task Clear(this IJSRuntime js) - { - await js.InvokeVoidAsync("BitButil.console.clear"); - } - - internal static async Task Count(this IJSRuntime js, string? label) - { - await js.InvokeVoidAsync("BitButil.console.count", label); - } - - internal static async Task CountReset(this IJSRuntime js, string? label) - { - await js.InvokeVoidAsync("BitButil.console.countReset", label); - } - - internal static async Task Debug(this IJSRuntime js, params object?[]? args) - { - await js.InvokeVoidAsync("BitButil.console.debug", args); - } - - internal static async Task Dir(this IJSRuntime js, object? item, object? options) - { - await js.InvokeVoidAsync("BitButil.console.dir", item, options); - } - - internal static async Task Dirxml(this IJSRuntime js, params object?[]? args) - { - await js.InvokeVoidAsync("BitButil.console.dirxml", args); - } - - internal static async Task Error(this IJSRuntime js, params object?[]? args) - { - await js.InvokeVoidAsync("BitButil.console.error", args); - } - - internal static async Task Group(this IJSRuntime js, params object?[]? args) - { - await js.InvokeVoidAsync("BitButil.console.group", args); - } - - internal static async Task GroupCollapsed(this IJSRuntime js, params object?[]? args) - { - await js.InvokeVoidAsync("BitButil.console.groupCollapsed", args); - } - - internal static async Task GroupEnd(this IJSRuntime js) - { - await js.InvokeVoidAsync("BitButil.console.groupEnd"); - } - - internal static async Task Info(this IJSRuntime js, params object?[]? args) - { - await js.InvokeVoidAsync("BitButil.console.info", args); - } - - internal static async Task Log(this IJSRuntime js, params object?[]? args) - { - await js.InvokeVoidAsync("BitButil.console.log", args); - } - - internal static async Task Memory(this IJSRuntime js) - { - await js.InvokeVoidAsync("BitButil.console.memory"); - } - - internal static async Task Profile(this IJSRuntime js) - { - await js.InvokeVoidAsync("BitButil.console.profile"); - } - - internal static async Task ProfileEnd(this IJSRuntime js) - { - await js.InvokeVoidAsync("BitButil.console.profileEnd"); - } - - internal static async Task Table(this IJSRuntime js, object? data, object? properties) - { - await js.InvokeVoidAsync("BitButil.console.table", data, properties); - } - - internal static async Task Time(this IJSRuntime js, string? label) - { - await js.InvokeVoidAsync("BitButil.console.time", label); - } - - internal static async Task TimeEnd(this IJSRuntime js, string? label) - { - await js.InvokeVoidAsync("BitButil.console.timeEnd", label); - } - - internal static async Task TimeLog(this IJSRuntime js, string? label, params object?[]? args) - { - await js.InvokeVoidAsync("BitButil.console.timeLog", [label, ..args]); - } - - internal static async Task TimeStamp(this IJSRuntime js, string? label) - { - await js.InvokeVoidAsync("BitButil.console.timeStamp", label); - } - - internal static async Task Trace(this IJSRuntime js, params object?[]? args) - { - await js.InvokeVoidAsync("BitButil.console.trace", args); - } - - internal static async Task Warn(this IJSRuntime js, params object?[]? args) - { - await js.InvokeVoidAsync("BitButil.console.warn", args); - } + internal static async Task ConsoleAssert(this IJSRuntime js, bool? condition, params object?[]? args) + => await js.InvokeVoidAsync("BitButil.console.assert", [condition, .. args]); + + internal static async Task ConsoleClear(this IJSRuntime js) + => await js.InvokeVoidAsync("BitButil.console.clear"); + + internal static async Task ConsoleCount(this IJSRuntime js, string? label) + => await js.InvokeVoidAsync("BitButil.console.count", label); + + internal static async Task ConsoleCountReset(this IJSRuntime js, string? label) + => await js.InvokeVoidAsync("BitButil.console.countReset", label); + + internal static async Task ConsoleDebug(this IJSRuntime js, params object?[]? args) + => await js.InvokeVoidAsync("BitButil.console.debug", args); + + internal static async Task ConsoleDir(this IJSRuntime js, object? item, object? options) + => await js.InvokeVoidAsync("BitButil.console.dir", item, options); + + internal static async Task ConsoleDirxml(this IJSRuntime js, params object?[]? args) + => await js.InvokeVoidAsync("BitButil.console.dirxml", args); + + internal static async Task ConsoleError(this IJSRuntime js, params object?[]? args) + => await js.InvokeVoidAsync("BitButil.console.error", args); + + internal static async Task ConsoleGroup(this IJSRuntime js, params object?[]? args) + => await js.InvokeVoidAsync("BitButil.console.group", args); + + internal static async Task ConsoleGroupCollapsed(this IJSRuntime js, params object?[]? args) + => await js.InvokeVoidAsync("BitButil.console.groupCollapsed", args); + + internal static async Task ConsoleGroupEnd(this IJSRuntime js) + => await js.InvokeVoidAsync("BitButil.console.groupEnd"); + + internal static async Task ConsoleInfo(this IJSRuntime js, params object?[]? args) + => await js.InvokeVoidAsync("BitButil.console.info", args); + + internal static async Task ConsoleLog(this IJSRuntime js, params object?[]? args) + => await js.InvokeVoidAsync("BitButil.console.log", args); + + internal static async Task ConsoleMemory(this IJSRuntime js) + => await js.InvokeVoidAsync("BitButil.console.memory"); + + internal static async Task ConsoleProfile(this IJSRuntime js) + => await js.InvokeVoidAsync("BitButil.console.profile"); + + internal static async Task ConsoleProfileEnd(this IJSRuntime js) + => await js.InvokeVoidAsync("BitButil.console.profileEnd"); + + internal static async Task ConsoleTable(this IJSRuntime js, object? data, object? properties) + => await js.InvokeVoidAsync("BitButil.console.table", data, properties); + + internal static async Task ConsoleTime(this IJSRuntime js, string? label) + => await js.InvokeVoidAsync("BitButil.console.time", label); + + internal static async Task ConsoleTimeEnd(this IJSRuntime js, string? label) + => await js.InvokeVoidAsync("BitButil.console.timeEnd", label); + + internal static async Task ConsoleTimeLog(this IJSRuntime js, string? label, params object?[]? args) + => await js.InvokeVoidAsync("BitButil.console.timeLog", [label, .. args]); + + internal static async Task ConsoleTimeStamp(this IJSRuntime js, string? label) + => await js.InvokeVoidAsync("BitButil.console.timeStamp", label); + + internal static async Task ConsoleTrace(this IJSRuntime js, params object?[]? args) + => await js.InvokeVoidAsync("BitButil.console.trace", args); + + internal static async Task ConsoleWarn(this IJSRuntime js, params object?[]? args) + => await js.InvokeVoidAsync("BitButil.console.warn", args); } diff --git a/src/Butil/Bit.Butil/Internals/JsInterops/ElementJsInterop.cs b/src/Butil/Bit.Butil/Internals/JsInterops/ElementJsInterop.cs new file mode 100644 index 0000000000..25ed235c24 --- /dev/null +++ b/src/Butil/Bit.Butil/Internals/JsInterops/ElementJsInterop.cs @@ -0,0 +1,122 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; + +namespace Bit.Butil; + +internal static class ElementJsInterop +{ + internal static async Task ElementBlur(this IJSRuntime js, ElementReference element) + => await js.InvokeVoidAsync("BitButil.element.blur", element); + + internal static async Task ElementGetAttribute(this IJSRuntime js, ElementReference element, string name) + => await js.InvokeAsync("BitButil.element.getAttribute", element, name); + + internal static async Task ElementGetAttributeNames(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.getAttribute", element); + + internal static async Task ElementGetBoundingClientRect(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.getBoundingClientRect", element); + + internal static async Task ElementHasAttribute(this IJSRuntime js, ElementReference element, string name) + => await js.InvokeAsync("BitButil.element.hasAttribute", element, name); + + internal static async Task ElementHasAttributes(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.hasAttributes", element); + + internal static async Task ElementHasPointerCapture(this IJSRuntime js, ElementReference element, int pointerId) + => await js.InvokeAsync("BitButil.element.hasPointerCapture", element, pointerId); + + internal static async Task ElementMatches(this IJSRuntime js, ElementReference element, string selectors) + => await js.InvokeAsync("BitButil.element.matches", element, selectors); + + internal static async Task ElementReleasePointerCapture(this IJSRuntime js, ElementReference element, int pointerId) + => await js.InvokeVoidAsync("BitButil.element.releasePointerCapture", element, pointerId); + + internal static async Task ElementRemove(this IJSRuntime js, ElementReference element) + => await js.InvokeVoidAsync("BitButil.element.remove", element); + + internal static async Task ElementRemoveAttribute(this IJSRuntime js, ElementReference element, string name) + => await js.InvokeAsync("BitButil.element.removeAttribute", element, name); + + internal static async Task ElementRequestFullScreen(this IJSRuntime js, ElementReference element, FullScreenOptions? options) + => await js.InvokeVoidAsync("BitButil.element.requestFullScreen", element, options); + + internal static async Task ElementRequestPointerLock(this IJSRuntime js, ElementReference element) + => await js.InvokeVoidAsync("BitButil.element.requestPointerLock", element); + + internal static async Task ElementScroll(this IJSRuntime js, ElementReference element, ScrollToOptions? options, double? x, double? y) + => await js.InvokeVoidAsync("BitButil.element.scroll", element, options, x, y); + + internal static async Task ElementScrollBy(this IJSRuntime js, ElementReference element, ScrollToOptions? options, double? x, double? y) + => await js.InvokeVoidAsync("BitButil.element.scrollBy", element, options, x, y); + + internal static async Task ElementScrollIntoView(this IJSRuntime js, ElementReference element, bool? alignToTop, ScrollIntoViewOptions? options) + => await js.InvokeVoidAsync("BitButil.element.scrollIntoView", element, alignToTop, options); + + internal static async Task ElementSetAttribute(this IJSRuntime js, ElementReference element, string name, string value) + => await js.InvokeVoidAsync("BitButil.element.setAttribute", element, name, value); + + internal static async Task ElementSetPointerCapture(this IJSRuntime js, ElementReference element, int pointerId) + => await js.InvokeVoidAsync("BitButil.element.setPointerCapture", element, pointerId); + + internal static async Task ElementToggleAttribute(this IJSRuntime js, ElementReference element, string name, bool? force) + => await js.InvokeVoidAsync("BitButil.element.toggleAttribute", element, name, force); + + internal static async Task ElementGetAccessKey(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.getAccessKey", element); + + internal static async Task ElementSetAccessKey(this IJSRuntime js, ElementReference element, string key) + => await js.InvokeVoidAsync("BitButil.element.setAccessKey", element, key); + + internal static async Task ElementGetClassName(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.getClassName", element); + + internal static async Task ElementSetClassName(this IJSRuntime js, ElementReference element, string className) + => await js.InvokeVoidAsync("BitButil.element.setClassName", element, className); + + internal static async Task ElementGetClientHeight(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.clientHeight", element); + + internal static async Task ElementGetClientLeft(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.clientLeft", element); + + internal static async Task ElementGetClientTop(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.clientTop", element); + + internal static async Task ElementGetClientWidth(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.clientWidth", element); + + internal static async Task ElementGetId(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.getId", element); + + internal static async Task ElementSetId(this IJSRuntime js, ElementReference element, string id) + => await js.InvokeVoidAsync("BitButil.element.setId", element, id); + + internal static async Task ElementGetInnerHTML(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.getInnerHTML", element); + + internal static async Task ElementSetInnerHTML(this IJSRuntime js, ElementReference element, string innerHTML) + => await js.InvokeVoidAsync("BitButil.element.setInnerHTML", element, innerHTML); + + internal static async Task ElementGetOuterHTML(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.getOuterHTML", element); + + internal static async Task ElementSetOuterHTML(this IJSRuntime js, ElementReference element, string outerHTML) + => await js.InvokeVoidAsync("BitButil.element.setOuterHTML", element, outerHTML); + + internal static async Task ElementGetScrollHeight(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.scrollHeight", element); + + internal static async Task ElementGetScrollLeft(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.scrollLeft", element); + + internal static async Task ElementGetScrollTop(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.scrollTop", element); + + internal static async Task ElementGetScrollWidth(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.scrollWidth", element); + + internal static async Task ElementGetTagName(this IJSRuntime js, ElementReference element) + => await js.InvokeAsync("BitButil.element.tagName", element); +} diff --git a/src/Butil/Bit.Butil/Internals/JsInterops/HistoryJsInterop.cs b/src/Butil/Bit.Butil/Internals/JsInterops/HistoryJsInterop.cs new file mode 100644 index 0000000000..c9cefc5d42 --- /dev/null +++ b/src/Butil/Bit.Butil/Internals/JsInterops/HistoryJsInterop.cs @@ -0,0 +1,44 @@ +using System; +using System.Threading.Tasks; +using Microsoft.JSInterop; + +namespace Bit.Butil; + +internal static class HistoryJsInterop +{ + internal static async Task HistoryGetLength(this IJSRuntime js) + => await js.InvokeAsync("BitButil.history.length"); + + internal static async Task HistoryGetScrollRestoration(this IJSRuntime js) + { + var value = await js.InvokeAsync("BitButil.history.scrollRestoration"); + return value == "auto" ? ScrollRestoration.Auto : ScrollRestoration.Manual; + } + + internal static async Task HistorySetScrollRestoration(this IJSRuntime js, ScrollRestoration value) + => await js.InvokeVoidAsync("BitButil.history.setScrollRestoration", value.ToString().ToLowerInvariant()); + + internal static async Task HistoryGetState(this IJSRuntime js) + => await js.InvokeAsync("BitButil.history.state"); + + internal static async Task HistoryGoBack(this IJSRuntime js) + => await js.InvokeVoidAsync("BitButil.history.back"); + + internal static async Task HistoryGoForward(this IJSRuntime js) + => await js.InvokeVoidAsync("BitButil.history.forward"); + + internal static async Task HistoryGo(this IJSRuntime js, int? delta) + => await js.InvokeVoidAsync("BitButil.history.go", delta); + + internal static async Task HistoryPushState(this IJSRuntime js, object? state, string unused, string? url) + => await js.InvokeVoidAsync("BitButil.history.pushState", state, unused, url); + + internal static async Task HistoryReplaceState(this IJSRuntime js, object? state, string unused, string? url) + => await js.InvokeVoidAsync("BitButil.history.replaceState", state, unused, url); + + internal static async Task HistoryAddPopState(this IJSRuntime js, string methodName, Guid listenerId) + => await js.InvokeVoidAsync("BitButil.history.addPopState", methodName, listenerId); + + internal static async Task HistoryRemovePopState(this IJSRuntime js, Guid[] ids) + => await js.InvokeVoidAsync("BitButil.history.removePopState", ids); +} diff --git a/src/Butil/Bit.Butil/Internals/JsInterops/KeyboardJsInterop.cs b/src/Butil/Bit.Butil/Internals/JsInterops/KeyboardJsInterop.cs index c60b6b48a4..1f2fe5709e 100644 --- a/src/Butil/Bit.Butil/Internals/JsInterops/KeyboardJsInterop.cs +++ b/src/Butil/Bit.Butil/Internals/JsInterops/KeyboardJsInterop.cs @@ -6,10 +6,10 @@ namespace Bit.Butil; internal static class KeyboardJsInterop { - internal static async Task AddKeyboard(this IJSRuntime js, + internal static async Task KeyboardAdd(this IJSRuntime js, string methodName, Guid listenerId, - string key, + string code, bool alt, bool ctrl, bool meta, @@ -21,7 +21,7 @@ internal static async Task AddKeyboard(this IJSRuntime js, await js.InvokeVoidAsync("BitButil.keyboard.add", methodName, listenerId, - key, + code, alt, ctrl, meta, @@ -31,7 +31,7 @@ await js.InvokeVoidAsync("BitButil.keyboard.add", repeat); } - internal static async Task RemoveKeyboard(this IJSRuntime js, Guid[] ids) + internal static async Task KeyboardRemove(this IJSRuntime js, Guid[] ids) { await js.InvokeVoidAsync("BitButil.keyboard.remove", ids); } diff --git a/src/Butil/Bit.Butil/Internals/JsInterops/NavigatorJsInterop.cs b/src/Butil/Bit.Butil/Internals/JsInterops/NavigatorJsInterop.cs new file mode 100644 index 0000000000..be8bb774bb --- /dev/null +++ b/src/Butil/Bit.Butil/Internals/JsInterops/NavigatorJsInterop.cs @@ -0,0 +1,52 @@ +using System.Threading.Tasks; +using Microsoft.JSInterop; + +namespace Bit.Butil; + +internal static class NavigatorJsInterop +{ + internal static async Task NavigatorDeviceMemory(this IJSRuntime js) + => await js.InvokeAsync("BitButil.navigator.deviceMemory"); + + internal static async Task NavigatorHardwareConcurrency(this IJSRuntime js) + => await js.InvokeAsync("BitButil.navigator.hardwareConcurrency"); + + internal static async Task NavigatorLanguage(this IJSRuntime js) + => await js.InvokeAsync("BitButil.navigator.language"); + + internal static async Task NavigatorLanguages(this IJSRuntime js) + => await js.InvokeAsync("BitButil.navigator.languages"); + + internal static async Task NavigatorMaxTouchPoints(this IJSRuntime js) + => await js.InvokeAsync("BitButil.navigator.maxTouchPoints"); + + internal static async Task NavigatorOnLine(this IJSRuntime js) + => await js.InvokeAsync("BitButil.navigator.onLine"); + + internal static async Task NavigatorPdfViewerEnabled(this IJSRuntime js) + => await js.InvokeAsync("BitButil.navigator.pdfViewerEnabled"); + + internal static async Task NavigatorUserAgent(this IJSRuntime js) + => await js.InvokeAsync("BitButil.navigator.userAgent"); + + internal static async Task NavigatorWebDriver(this IJSRuntime js) + => await js.InvokeAsync("BitButil.navigator.webdriver"); + + internal static async Task NavigatorCanShare(this IJSRuntime js) + => await js.InvokeAsync("BitButil.navigator.canShare"); + + internal static async Task NavigatorClearAppBadge(this IJSRuntime js) + => await js.InvokeVoidAsync("BitButil.navigator.clearAppBadge"); + + internal static async Task NavigatorSendBeacon(this IJSRuntime js) + => await js.InvokeAsync("BitButil.navigator.sendBeacon"); + + internal static async Task NavigatorSetAppBadge(this IJSRuntime js) + => await js.InvokeVoidAsync("BitButil.navigator.setAppBadge"); + + internal static async Task NavigatorShare(this IJSRuntime js, ShareData data) + => await js.InvokeVoidAsync("BitButil.navigator.share", data); + + internal static async Task NavigatorVibrate(this IJSRuntime js, int[] pattern) + => await js.InvokeAsync("BitButil.navigator.vibrate", pattern); +} diff --git a/src/Butil/Bit.Butil/Internals/JsInterops/WindowJsInterop.cs b/src/Butil/Bit.Butil/Internals/JsInterops/WindowJsInterop.cs index 845b1d8248..f70ba31e0e 100644 --- a/src/Butil/Bit.Butil/Internals/JsInterops/WindowJsInterop.cs +++ b/src/Butil/Bit.Butil/Internals/JsInterops/WindowJsInterop.cs @@ -5,13 +5,9 @@ namespace Bit.Butil; internal static class WindowJsInterop { - internal static async Task AddBeforeUnload(this IJSRuntime js) - { - await js.InvokeVoidAsync("BitButil.window.addBeforeUnload"); - } + internal static async Task WindowAddBeforeUnload(this IJSRuntime js) + => await js.InvokeVoidAsync("BitButil.window.addBeforeUnload"); - internal static async Task RemoveBeforeUnload(this IJSRuntime js) - { - await js.InvokeVoidAsync("BitButil.window.removeBeforeUnload"); - } + internal static async Task WindowRemoveBeforeUnload(this IJSRuntime js) + => await js.InvokeVoidAsync("BitButil.window.removeBeforeUnload"); } diff --git a/src/Butil/Bit.Butil/Publics/Console.cs b/src/Butil/Bit.Butil/Publics/Console.cs index ba663f64ef..210d7cfc2d 100644 --- a/src/Butil/Bit.Butil/Publics/Console.cs +++ b/src/Butil/Bit.Butil/Publics/Console.cs @@ -6,117 +6,71 @@ namespace Bit.Butil; public class Console(IJSRuntime js) { public async Task Assert(bool? condition, params object?[]? args) - { - await js.Assert(condition, args); - } + => await js.ConsoleAssert(condition, args); public async Task Clear() - { - await js.Clear(); - } + => await js.ConsoleClear(); public async Task Count(string? label) - { - await js.Count(label); - } + => await js.ConsoleCount(label); public async Task CountReset(string? label) - { - await js.CountReset(label); - } + => await js.ConsoleCountReset(label); public async Task Debug(params object?[]? args) - { - await js.Debug(args); - } + => await js.ConsoleDebug(args); public async Task Dir(object? item, object? options) - { - await js.Dir(item, options); - } + => await js.ConsoleDir(item, options); public async Task Dirxml(params object?[]? args) - { - await js.Dirxml(args); - } + => await js.ConsoleDirxml(args); public async Task Error(params object?[]? args) - { - await js.Error(args); - } + => await js.ConsoleError(args); public async Task Group(params object?[]? args) - { - await js.Group(args); - } + => await js.ConsoleGroup(args); public async Task GroupCollapsed(params object?[]? args) - { - await js.GroupCollapsed(args); - } + => await js.ConsoleGroupCollapsed(args); public async Task GroupEnd() - { - await js.GroupEnd(); - } + => await js.ConsoleGroupEnd(); public async Task Info(params object?[]? args) - { - await js.Info(args); - } + => await js.ConsoleInfo(args); public async Task Log(params object?[]? args) - { - await js.Log(args); - } + => await js.ConsoleLog(args); public async Task Memory() - { - await js.Memory(); - } + => await js.ConsoleMemory(); public async Task Profile() - { - await js.Profile(); - } + => await js.ConsoleProfile(); public async Task ProfileEnd() - { - await js.ProfileEnd(); - } + => await js.ConsoleProfileEnd(); public async Task Table(object? data, object? properties) - { - await js.Table(data, properties); - } + => await js.ConsoleTable(data, properties); public async Task Time(string? label) - { - await js.Time(label); - } + => await js.ConsoleTime(label); public async Task TimeEnd(string? label) - { - await js.TimeEnd(label); - } + => await js.ConsoleTimeEnd(label); public async Task TimeLog(string? label, params object?[]? args) - { - await js.TimeLog(label, args); - } + => await js.ConsoleTimeLog(label, args); public async Task TimeStamp(string? label) - { - await js.TimeStamp(label); - } + => await js.ConsoleTimeStamp(label); public async Task Trace(params object?[]? args) - { - await js.Trace(args); - } + => await js.ConsoleTrace(args); public async Task Warn(params object?[]? args) - { - await js.Warn(args); - } + => await js.ConsoleWarn(args); } diff --git a/src/Butil/Bit.Butil/Publics/Element.cs b/src/Butil/Bit.Butil/Publics/Element.cs new file mode 100644 index 0000000000..da72e5282f --- /dev/null +++ b/src/Butil/Bit.Butil/Publics/Element.cs @@ -0,0 +1,275 @@ +using System.Threading.Tasks; +using Microsoft.JSInterop; +using Microsoft.AspNetCore.Components; + +namespace Bit.Butil; + +/// +/// Element is the most general base class from which all element objects (i.e. objects that represent elements) in a Document inherit. +/// It only has methods and properties common to all kinds of elements. More specific classes inherit from Element. +/// The HTMLElement interface represents any HTML element. Some elements directly implement this interface, +/// while others implement it via an interface that inherits it. +///
+/// More infor: +/// More infor: +///
+public class Element(IJSRuntime js) +{ + /// + /// Removes keyboard focus from the currently focused element. + /// + public async Task Blur(ElementReference element) + => await js.ElementBlur(element); + + /// + /// Retrieves the value of the named attribute from the current node and returns it as a string. + /// + public async Task GetAttribute(ElementReference element, string name) + => await js.ElementGetAttribute(element, name); + + /// + /// Returns an array of attribute names from the current element. + /// + public async Task GetAttributeNames(ElementReference element) + => await js.ElementGetAttributeNames(element); + + /// + /// Returns the size of an element and its position relative to the viewport. + /// + public async Task GetBoundingClientRect(ElementReference element) + => await js.ElementGetBoundingClientRect(element); + + /// + /// Returns a boolean value indicating if the element has the specified attribute or not. + /// + public async Task HasAttribute(ElementReference element, string name) + => await js.ElementHasAttribute(element, name); + + /// + /// Returns a boolean value indicating if the element has one or more HTML attributes present. + /// + public async Task HasAttributes(ElementReference element) + => await js.ElementHasAttributes(element); + + /// + /// Indicates whether the element on which it is invoked has pointer capture for the pointer identified by the given pointer ID. + /// + public async Task HasPointerCapture(ElementReference element, int pointerId) + => await js.ElementHasPointerCapture(element, pointerId); + + /// + /// Returns a boolean value indicating whether or not the element would be selected by the specified selector string. + /// + public async Task Matches(ElementReference element, string selectors) + => await js.ElementMatches(element, selectors); + + /// + /// Releases (stops) pointer capture that was previously set for a specific pointer event. + /// + public async Task ReleasePointerCapture(ElementReference element, int pointerId) + => await js.ElementReleasePointerCapture(element, pointerId); + + /// + /// Removes the element from the children list of its parent. + /// + public async Task Remove(ElementReference element) + => await js.ElementRemove(element); + + /// + /// Removes the named attribute from the current node. + /// + public async Task RemoveAttribute(ElementReference element, string name) + => await js.ElementRemoveAttribute(element, name); + + /// + /// Asynchronously asks the browser to make the element fullscreen. + /// + public async Task RequestFullScreen(ElementReference element, FullScreenOptions? options) + => await js.ElementRequestFullScreen(element, options); + + /// + /// Allows to asynchronously ask for the pointer to be locked on the given element. + /// + public async Task RequestPointerLock(ElementReference element) + => await js.ElementRequestPointerLock(element); + + /// + /// Scrolls to a particular set of coordinates inside a given element. + /// + public async Task Scroll(ElementReference element, ScrollToOptions? options) + => await js.ElementScroll(element, options, null, null); + /// + /// Scrolls to a particular set of coordinates inside a given element. + /// + public async Task Scroll(ElementReference element, double? x, double? y) + => await js.ElementScroll(element, null, x, y); + /// + /// Scrolls to a particular set of coordinates inside a given element. + /// + public async Task Scroll(ElementReference element, ScrollToOptions? options, double? x, double? y) + => await js.ElementScroll(element, options, x, y); + + /// + /// Scrolls an element by the given amount. + /// + public async Task ScrollBy(ElementReference element, ScrollToOptions? options) + => await js.ElementScrollBy(element, options, null, null); + /// + /// Scrolls an element by the given amount. + /// + public async Task ScrollBy(ElementReference element, double? x, double? y) + => await js.ElementScrollBy(element, null, x, y); + /// + /// Scrolls an element by the given amount. + /// + public async Task ScrollBy(ElementReference element, ScrollToOptions? options, double? x, double? y) + => await js.ElementScrollBy(element, options, x, y); + + /// + /// Scrolls the page until the element gets into the view. + /// + public async Task ScrollIntoView(ElementReference element) + => await ScrollIntoView(element, null, null); + /// + /// Scrolls the page until the element gets into the view. + /// + public async Task ScrollIntoView(ElementReference element, bool alignToTop) + => await ScrollIntoView(element, alignToTop, null); + /// + /// Scrolls the page until the element gets into the view. + /// + public async Task ScrollIntoView(ElementReference element, ScrollIntoViewOptions options) + => await ScrollIntoView(element, null, options); + /// + /// Scrolls the page until the element gets into the view. + /// + public async Task ScrollIntoView(ElementReference element, bool? alignToTop, ScrollIntoViewOptions? options) + => await js.ElementScrollIntoView(element, alignToTop, options); + + /// + /// Sets the value of a named attribute of the current node. + /// + public async Task SetAttribute(ElementReference element, string name, string value) + => await js.ElementSetAttribute(element, name, value); + + /// + /// Designates a specific element as the capture target of future pointer events. + /// + public async Task SetPointerCapture(ElementReference element, int pointerId) + => await js.ElementSetPointerCapture(element, pointerId); + + /// + /// Toggles a boolean attribute, removing it if it is present and adding it if it is not present, on the specified element. + /// + public async Task ToggleAttribute(ElementReference element, string name, bool? force = null) + => await js.ElementToggleAttribute(element, name, force); + + /// + /// A string representing the access key assigned to the element. + /// + public async Task GetAccessKey(ElementReference element) + => await js.ElementGetAccessKey(element); + /// + /// A string representing the access key assigned to the element. + /// + public async Task SetAccessKey(ElementReference element, string key) + => await js.ElementSetAccessKey(element, key); + + /// + /// A string representing the class of the element. + /// + public async Task GetClassName(ElementReference element) + => await js.ElementGetClassName(element); + /// + /// A string representing the class of the element. + /// + public async Task SetClassName(ElementReference element, string className) + => await js.ElementSetClassName(element, className); + + /// + /// Returns a number representing the inner height of the element in px. + /// + public async Task GetClientHeight(ElementReference element) + => await js.ElementGetClientHeight(element); + + /// + /// Returns a number representing the width of the left border of the element in px. + /// + public async Task GetClientLeft(ElementReference element) + => await js.ElementGetClientLeft(element); + + /// + /// Returns a number representing the width of the top border of the element in px. + /// + public async Task GetClientTop(ElementReference element) + => await js.ElementGetClientTop(element); + + /// + /// Returns a number representing the inner width of the element in px. + /// + public async Task GetClientWidth(ElementReference element) + => await js.ElementGetClientWidth(element); + + /// + /// A string representing the id of the element. + /// + public async Task GetId(ElementReference element) + => await js.ElementGetId(element); + /// + /// A string representing the id of the element. + /// + public async Task SetId(ElementReference element, string id) + => await js.ElementSetId(element, id); + + /// + /// A string representing the markup of the element's content. + /// + public async Task GetInnerHtml(ElementReference element) + => await js.ElementGetInnerHTML(element); + /// + /// A string representing the markup of the element's content. + /// + public async Task SetInnerHtml(ElementReference element, string innerHtml) + => await js.ElementSetInnerHTML(element, innerHtml); + + /// + /// A string representing the markup of the element including its content. + /// + public async Task GetOuterHtml(ElementReference element) + => await js.ElementGetOuterHTML(element); + /// + /// A string representing the markup of the element including its content. When used as a setter, replaces the element with nodes parsed from the given string. + /// + public async Task SetOuterHtml(ElementReference element, string outerHtml) + => await js.ElementSetOuterHTML(element, outerHtml); + + /// + /// Returns a number representing the scroll view height of an element. + /// + public async Task GetScrollHeight(ElementReference element) + => await js.ElementGetScrollHeight(element); + + /// + /// A number representing the left scroll offset of the element. + /// + public async Task GetScrollLeft(ElementReference element) + => await js.ElementGetScrollLeft(element); + + /// + /// A number representing number of pixels the top of the element is scrolled vertically. + /// + public async Task GetScrollTop(ElementReference element) + => await js.ElementGetScrollTop(element); + + /// + /// Returns a number representing the scroll view width of the element. + /// + public async Task GetScrollWidth(ElementReference element) + => await js.ElementGetScrollWidth(element); + + /// + /// Returns a string with the name of the tag for the given element. + /// + public async Task GetTagName(ElementReference element) + => await js.ElementGetScrollWidth(element); +} diff --git a/src/Butil/Bit.Butil/Publics/Element/DomRect.cs b/src/Butil/Bit.Butil/Publics/Element/DomRect.cs new file mode 100644 index 0000000000..4098f7d025 --- /dev/null +++ b/src/Butil/Bit.Butil/Publics/Element/DomRect.cs @@ -0,0 +1,9 @@ +namespace Bit.Butil; + +public class DomRect +{ + public double Height { get; set; } + public double Width { get; set; } + public double X { get; set; } + public double Y { get; set; } +} diff --git a/src/Butil/Bit.Butil/Publics/Element/FullscreenNavigationUI.cs b/src/Butil/Bit.Butil/Publics/Element/FullscreenNavigationUI.cs new file mode 100644 index 0000000000..9008a32128 --- /dev/null +++ b/src/Butil/Bit.Butil/Publics/Element/FullscreenNavigationUI.cs @@ -0,0 +1,8 @@ +namespace Bit.Butil; + +public enum FullScreenNavigationUI +{ + Auto, + Hide, + Show +} diff --git a/src/Butil/Bit.Butil/Publics/Element/FullscreenOptions.cs b/src/Butil/Bit.Butil/Publics/Element/FullscreenOptions.cs new file mode 100644 index 0000000000..88dde4f1bd --- /dev/null +++ b/src/Butil/Bit.Butil/Publics/Element/FullscreenOptions.cs @@ -0,0 +1,6 @@ +namespace Bit.Butil; + +public class FullScreenOptions +{ + public FullScreenNavigationUI? NavigationUI { get; set; } +} diff --git a/src/Butil/Bit.Butil/Publics/Element/ScrollBehavior.cs b/src/Butil/Bit.Butil/Publics/Element/ScrollBehavior.cs new file mode 100644 index 0000000000..81af34bb07 --- /dev/null +++ b/src/Butil/Bit.Butil/Publics/Element/ScrollBehavior.cs @@ -0,0 +1,8 @@ +namespace Bit.Butil; + +public enum ScrollBehavior +{ + Auto, + Instant, + Smooth +} diff --git a/src/Butil/Bit.Butil/Publics/Element/ScrollIntoViewOptions.cs b/src/Butil/Bit.Butil/Publics/Element/ScrollIntoViewOptions.cs new file mode 100644 index 0000000000..292645cdc5 --- /dev/null +++ b/src/Butil/Bit.Butil/Publics/Element/ScrollIntoViewOptions.cs @@ -0,0 +1,10 @@ +namespace Bit.Butil; + +public class ScrollIntoViewOptions +{ + public ScrollBehavior? behavior { get; set; } + + public ScrollLogicalPosition? Block { get; set; } + + public ScrollLogicalPosition? Inline { get; set; } +} diff --git a/src/Butil/Bit.Butil/Publics/Element/ScrollLogicalPosition.cs b/src/Butil/Bit.Butil/Publics/Element/ScrollLogicalPosition.cs new file mode 100644 index 0000000000..32032a7094 --- /dev/null +++ b/src/Butil/Bit.Butil/Publics/Element/ScrollLogicalPosition.cs @@ -0,0 +1,9 @@ +namespace Bit.Butil; + +public enum ScrollLogicalPosition +{ + Start, + Center, + End, + Nearest +} diff --git a/src/Butil/Bit.Butil/Publics/Element/ScrollToOptions.cs b/src/Butil/Bit.Butil/Publics/Element/ScrollToOptions.cs new file mode 100644 index 0000000000..c87e6a4f86 --- /dev/null +++ b/src/Butil/Bit.Butil/Publics/Element/ScrollToOptions.cs @@ -0,0 +1,10 @@ +namespace Bit.Butil; + +public class ScrollToOptions +{ + public ScrollBehavior? behavior { get; set; } + + public double? Top { get; set; } + + public double? Left { get; set; } +} diff --git a/src/Butil/Bit.Butil/Publics/Events/ButilKeyCodes.cs b/src/Butil/Bit.Butil/Publics/Events/ButilKeyCodes.cs new file mode 100644 index 0000000000..07b7891ec5 --- /dev/null +++ b/src/Butil/Bit.Butil/Publics/Events/ButilKeyCodes.cs @@ -0,0 +1,120 @@ +namespace Bit.Butil; + +public static class ButilKeyCodes +{ + // Letters + public const string KeyA = "KeyA"; + public const string KeyB = "KeyB"; + public const string KeyC = "KeyC"; + public const string KeyD = "KeyD"; + public const string KeyE = "KeyE"; + public const string KeyF = "KeyF"; + public const string KeyG = "KeyG"; + public const string KeyH = "KeyH"; + public const string KeyI = "KeyI"; + public const string KeyJ = "KeyJ"; + public const string KeyK = "KeyK"; + public const string KeyL = "KeyL"; + public const string KeyM = "KeyM"; + public const string KeyN = "KeyN"; + public const string KeyO = "KeyO"; + public const string KeyP = "KeyP"; + public const string KeyQ = "KeyQ"; + public const string KeyR = "KeyR"; + public const string KeyS = "KeyS"; + public const string KeyT = "KeyT"; + public const string KeyU = "KeyU"; + public const string KeyV = "KeyV"; + public const string KeyW = "KeyW"; + public const string KeyX = "KeyX"; + public const string KeyY = "KeyY"; + public const string KeyZ = "KeyZ"; + + // Digits + public const string Digit0 = "Digit0"; + public const string Digit1 = "Digit1"; + public const string Digit2 = "Digit2"; + public const string Digit3 = "Digit3"; + public const string Digit4 = "Digit4"; + public const string Digit5 = "Digit5"; + public const string Digit6 = "Digit6"; + public const string Digit7 = "Digit7"; + public const string Digit8 = "Digit8"; + public const string Digit9 = "Digit9"; + + public const string Numpad0 = "Numpad0"; + public const string Numpad1 = "Numpad1"; + public const string Numpad2 = "Numpad2"; + public const string Numpad3 = "Numpad3"; + public const string Numpad4 = "Numpad4"; + public const string Numpad5 = "Numpad5"; + public const string Numpad6 = "Numpad6"; + public const string Numpad7 = "Numpad7"; + public const string Numpad8 = "Numpad8"; + public const string Numpad9 = "Numpad9"; + public const string NumLock = "NumLock"; + public const string NumpadAdd = "NumpadAdd"; + public const string NumpadMultiply = "NumpadMultiply"; + public const string NumpadSubtract = "NumpadSubtract"; + public const string NumpadDecimal = "NumpadDecimal"; + public const string NumpadDivide = "NumpadDivide"; + public const string NumpadEnter = "NumpadEnter"; + public const string NumpadEqual = "NumpadEqual"; + public const string NumpadComma = "NumpadComma"; + + // Function keys + public const string F1 = "F1"; + public const string F2 = "F2"; + public const string F3 = "F3"; + public const string F4 = "F4"; + public const string F5 = "F5"; + public const string F6 = "F6"; + public const string F7 = "F7"; + public const string F8 = "F8"; + public const string F9 = "F9"; + public const string F10 = "F10"; + public const string F11 = "F11"; + public const string F12 = "F12"; + + public const string Backspace = "Backspace"; + public const string Tab = "Tab"; + public const string Enter = "Enter"; + public const string ShiftLeft = "ShiftLeft"; + public const string ShiftRight = "ShiftRight"; + public const string ControlLeft = "ControlLeft"; + public const string ControlRight = "ControlRight"; + public const string AltLeft = "AltLeft"; + public const string AltRight = "AltRight"; + public const string PauseBreak = "Pause"; + public const string CapsLock = "CapsLock"; + public const string Escape = "Escape"; + public const string Space = "Space"; + public const string PageUp = "PageUp"; + public const string PageDown = "PageDown"; + public const string End = "End"; + public const string Home = "Home"; + public const string ArrowLeft = "ArrowLeft"; + public const string ArrowUp = "ArrowUp"; + public const string ArrowRight = "ArrowRight"; + public const string ArrowDown = "ArrowDown"; + public const string PrintScreen = "PrintScreen"; + public const string Insert = "Insert"; + public const string Delete = "Delete"; + public const string MetaLeft = "MetaLeft"; + public const string MetaRight = "MetaRight"; + public const string ContextMenu = "ContextMenu"; + public const string ScrollLock = "ScrollLock"; + + // Symbols + public const string Semicolon = "Semicolon"; + public const string Equal = "Equal"; + public const string Comma = "Comma"; + public const string Minus = "Minus"; + public const string Period = "Period"; + public const string Slash = "Slash"; + public const string Backquote = "Backquote"; + public const string BracketLeft = "BracketLeft"; + public const string Backslash = "Backslash"; + public const string BracketRight = "BracketRight"; + public const string Quote = "Quote"; +} diff --git a/src/Butil/Bit.Butil/Publics/Events/ButilKeys.cs b/src/Butil/Bit.Butil/Publics/Events/ButilKeys.cs deleted file mode 100644 index b9bfae2850..0000000000 --- a/src/Butil/Bit.Butil/Publics/Events/ButilKeys.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Bit.Butil; - -public static class ButilKeys -{ - public const string A = "A"; - public const string B = "B"; -} diff --git a/src/Butil/Bit.Butil/Publics/History.cs b/src/Butil/Bit.Butil/Publics/History.cs new file mode 100644 index 0000000000..5ffa1433fc --- /dev/null +++ b/src/Butil/Bit.Butil/Publics/History.cs @@ -0,0 +1,125 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using System.Collections.Concurrent; +using Microsoft.JSInterop; + +namespace Bit.Butil; + +/// +/// The History interface allows manipulation of the browser session history, that is the pages visited in the tab or frame that the current page is loaded in. +///
+/// More info: https://developer.mozilla.org/en-US/docs/Web/API/History +///
+public class History(IJSRuntime js) : IDisposable +{ + private readonly ConcurrentDictionary> _handlers = new(); + + /// + /// Returns an Integer representing the number of elements in the session history, including the currently loaded page. + /// For example, for a page loaded in a new tab this property returns 1. + /// + public async Task GetLength() => await js.HistoryGetLength(); + + /// + /// Gets default scroll restoration behavior on history navigation. This property can be either auto or manual. + /// + public async Task GetScrollRestoration() => await js.HistoryGetScrollRestoration(); + + /// + /// Allows web applications to explicitly set default scroll restoration behavior on history navigation. This property can be either auto or manual. + /// + public async Task SetScrollRestoration(ScrollRestoration value) => await js.HistorySetScrollRestoration(value); + + /// + /// Returns an any value representing the state at the top of the history stack. + /// + public async Task GetState() => await js.HistoryGetState(); + + /// + /// This asynchronous method goes to the previous page in session history, the same action as when the user clicks the browser's Back button. + /// Calling this method to go back beyond the first page in the session history has no effect and doesn't raise an exception. + /// + public async Task GoBack() => await js.HistoryGoBack(); + + /// + /// This asynchronous method goes to the next page in session history, the same action as when the user clicks the browser's Forward button. + /// Calling this method to go forward beyond the most recent page in the session history has no effect and doesn't raise an exception. + /// + /// + public async Task GoForward() => await js.HistoryGoForward(); + + /// + /// Asynchronously loads a page from the session history, identified by its relative location to the current page, for example -1 for the previous page or 1 for the next page. + /// Calling this method without parameters or a value of 0 reloads the current page. + /// + public async Task Go(int? delta = null) => await js.HistoryGo(delta); + + /// + /// Pushes the given data onto the session history stack with the specified title (and, if provided, URL). + /// + /// The state object can be anything that can be serialized. + /// The new history entry's URL. The new URL must be of the same origin as the current URL; otherwise PushState throws an exception. + public async Task PushState(object? state = null, string? url = null) => await js.HistoryPushState(state, string.Empty, url); + + /// + /// Updates the most recent entry on the history stack to have the specified data, title, and, if provided, URL. + /// + /// An object which is associated with the history entry passed to the ReplaceState() method. The state object can be null. + /// The URL of the history entry. The new URL must be of the same origin as the current URL; otherwise ReplaceState throws an exception. + public async Task ReplaceState(object? state = null, string? url = null) => await js.HistoryReplaceState(state, string.Empty, url); + + /// + /// The popstate event of the Window interface is fired when the active history entry changes while the user navigates the session history. + /// + public async Task AddPopState(Action handler) + { + var listenerId = HistoryListenersManager.AddListener(handler); + _handlers.TryAdd(listenerId, handler); + + await js.HistoryAddPopState(HistoryListenersManager.InvokeMethodName, listenerId); + + return listenerId; + } + + /// + /// The popstate event of the Window interface is fired when the active history entry changes while the user navigates the session history. + /// + public Guid[] RemovePopState(Action handler) + { + var ids = HistoryListenersManager.RemoveListener(handler); + + RemovePopState(ids); + + return ids; + } + + /// + /// The popstate event of the Window interface is fired when the active history entry changes while the user navigates the session history. + /// + public void RemovePopState(Guid id) + { + HistoryListenersManager.RemoveListeners([id]); + + RemovePopState([id]); + } + + private void RemovePopState(Guid[] ids) + { + foreach (var id in ids) + { + _handlers.TryRemove(id, out _); + } + + _ = js.HistoryRemovePopState(ids); + } + + public void Dispose() + { + var ids = _handlers.Select(h => h.Key).ToArray(); + + HistoryListenersManager.RemoveListeners(ids); + + _ = js.HistoryRemovePopState(ids); + } +} diff --git a/src/Butil/Bit.Butil/Publics/History/ScrollRestoration.cs b/src/Butil/Bit.Butil/Publics/History/ScrollRestoration.cs new file mode 100644 index 0000000000..8baf0c0dc9 --- /dev/null +++ b/src/Butil/Bit.Butil/Publics/History/ScrollRestoration.cs @@ -0,0 +1,14 @@ +namespace Bit.Butil; + +public enum ScrollRestoration +{ + /// + /// The location on the page to which the user has scrolled will be restored. + /// + Auto, + + /// + /// The location on the page is not restored. The user will have to scroll to the location manually. + /// + Manual +} diff --git a/src/Butil/Bit.Butil/Publics/Keyboard.cs b/src/Butil/Bit.Butil/Publics/Keyboard.cs index d24b4d8e97..2d2ce1e162 100644 --- a/src/Butil/Bit.Butil/Publics/Keyboard.cs +++ b/src/Butil/Bit.Butil/Publics/Keyboard.cs @@ -1,7 +1,7 @@ using System; -using System.Collections.Concurrent; using System.Linq; using System.Threading.Tasks; +using System.Collections.Concurrent; using Microsoft.JSInterop; namespace Bit.Butil; @@ -10,12 +10,12 @@ public class Keyboard(IJSRuntime js) : IDisposable { private readonly ConcurrentDictionary _handlers = new(); - public async Task Add(string key, Action handler, ButilModifiers modifiers = ButilModifiers.None, bool preventDefault = true, bool stopPropagation = true, bool repeat = false) + public async Task Add(string code, Action handler, ButilModifiers modifiers = ButilModifiers.None, bool preventDefault = true, bool stopPropagation = true, bool repeat = false) { var listenerId = KeyboardListenersManager.AddListener(handler); _handlers.TryAdd(listenerId, handler); - await js.AddKeyboard(KeyboardListenersManager.InvokeMethodName, listenerId, key, + await js.KeyboardAdd(KeyboardListenersManager.InvokeMethodName, listenerId, code, modifiers.HasFlag(ButilModifiers.Alt), modifiers.HasFlag(ButilModifiers.Ctrl), modifiers.HasFlag(ButilModifiers.Meta), @@ -50,7 +50,7 @@ private void Remove(Guid[] ids) _handlers.TryRemove(id, out _); } - _ = js.RemoveKeyboard(ids); + _ = js.KeyboardRemove(ids); } public void Dispose() @@ -59,13 +59,6 @@ public void Dispose() KeyboardListenersManager.RemoveListeners(ids); - _ = js.RemoveKeyboard(ids); - } - - private class Listener - { - public string? Key { get; set; } - public Action? Handler { get; set; } - public ButilModifiers Modifiers { get; set; } + _ = js.KeyboardRemove(ids); } } diff --git a/src/Butil/Bit.Butil/Publics/Navigator.cs b/src/Butil/Bit.Butil/Publics/Navigator.cs new file mode 100644 index 0000000000..ddf06b92c6 --- /dev/null +++ b/src/Butil/Bit.Butil/Publics/Navigator.cs @@ -0,0 +1,87 @@ +using System.Threading.Tasks; +using Microsoft.JSInterop; + +namespace Bit.Butil; + +/// +/// The Navigator interface represents the state and the identity of the user agent. It allows scripts to query it and to register themselves to carry on some activities. +///
+/// More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator +///
+public class Navigator(IJSRuntime js) +{ + /// + /// Returns the amount of device memory in gigabytes. This value is an approximation given by rounding to the nearest power of 2 and dividing that number by 1024. + /// + public async Task GetDeviceMemory() => await js.NavigatorDeviceMemory(); + + /// + /// Returns the number of logical processor cores available. + /// + public async Task GetHardwareConcurrency() => await js.NavigatorHardwareConcurrency(); + + /// + /// Returns a string representing the preferred language of the user, usually the language of the browser UI. The null value is returned when this is unknown. + /// + public async Task GetLanguage() => await js.NavigatorLanguage(); + + /// + /// Returns an array of strings representing the languages known to the user, by order of preference. + /// + public async Task GetLanguages() => await js.NavigatorLanguages(); + + /// + /// Returns the maximum number of simultaneous touch contact points are supported by the current device. + /// + public async Task GetMaxTouchPoints() => await js.NavigatorMaxTouchPoints(); + + /// + /// Returns a boolean value indicating whether the browser is working online. + /// + public async Task IsOnLine() => await js.NavigatorOnLine(); + + /// + /// Returns true if the browser can display PDF files inline when navigating to them, and false otherwise. + /// + public async Task IsPdfViewerEnabled() => await js.NavigatorPdfViewerEnabled(); + + /// + /// Returns the user agent string for the current browser. + /// + public async Task GetUserAgent() => await js.NavigatorUserAgent(); + + /// + /// Indicates whether the user agent is controlled by automation. + /// + public async Task IsWebDriver() => await js.NavigatorWebDriver(); + + /// + /// Returns true if a call to Navigator.share() would succeed. + /// + public async Task CanShare() => await js.NavigatorCanShare(); + + /// + /// Clears a badge on the current app's icon and returns a Promise that resolves with undefined. + /// + public async Task ClearAppBadge() => await js.NavigatorClearAppBadge(); + + /// + /// Used to asynchronously transfer a small amount of data using HTTP from the User Agent to a web server. + /// + public async Task SendBeacon() => await js.NavigatorSendBeacon(); + + /// + /// Sets a badge on the icon associated with this app and returns a Promise that resolves with undefined. + /// + public async Task SetAppBadge() => await js.NavigatorSetAppBadge(); + + /// + /// Invokes the native sharing mechanism of the current platform. + /// + public async Task Share(ShareData data) => await js.NavigatorShare(data); + + /// + /// Causes vibration on devices with support for it. Does nothing if vibration support isn't available. + /// + public async Task Vibrate(int[] pattern) => await js.NavigatorVibrate(pattern); +} diff --git a/src/Butil/Bit.Butil/Publics/Navigator/ShareData.cs b/src/Butil/Bit.Butil/Publics/Navigator/ShareData.cs new file mode 100644 index 0000000000..6acb79f966 --- /dev/null +++ b/src/Butil/Bit.Butil/Publics/Navigator/ShareData.cs @@ -0,0 +1,9 @@ +namespace Bit.Butil; + +public class ShareData +{ + // files?: File[]; + public string? Text { get; set; } + public string? title { get; set; } + public string? url { get; set; } +} diff --git a/src/Butil/Bit.Butil/Publics/Window.cs b/src/Butil/Bit.Butil/Publics/Window.cs index a3530b629e..e171de887b 100644 --- a/src/Butil/Bit.Butil/Publics/Window.cs +++ b/src/Butil/Bit.Butil/Publics/Window.cs @@ -9,22 +9,14 @@ public class Window(IJSRuntime js) private const string ElementName = "window"; public async Task AddEventListener(string domEvent, Action listener, bool useCapture = false) - { - await DomEventDispatcher.AddEventListener(js, ElementName, domEvent, listener, useCapture); - } + => await DomEventDispatcher.AddEventListener(js, ElementName, domEvent, listener, useCapture); public async Task RemoveEventListener(string domEvent, Action listener, bool useCapture = false) - { - await DomEventDispatcher.RemoveEventListener(js, ElementName, domEvent, listener, useCapture); - } + => await DomEventDispatcher.RemoveEventListener(js, ElementName, domEvent, listener, useCapture); public async Task AddBeforeUnload() - { - await js.AddBeforeUnload(); - } + => await js.WindowAddBeforeUnload(); public async Task RemoveBeforeUnload() - { - await js.RemoveBeforeUnload(); - } + => await js.WindowRemoveBeforeUnload(); } diff --git a/src/Butil/Bit.Butil/Scripts/element.ts b/src/Butil/Bit.Butil/Scripts/element.ts new file mode 100644 index 0000000000..b08c18965b --- /dev/null +++ b/src/Butil/Bit.Butil/Scripts/element.ts @@ -0,0 +1,199 @@ +var BitButil = BitButil || {}; + +(function (butil: any) { + butil.element = { + blur, + getAttribute, + getAttributeNames, + getBoundingClientRect, + hasAttribute, + hasAttributes, + hasPointerCapture, + matches, + releasePointerCapture, + remove, + removeAttribute, + requestFullScreen, + requestPointerLock, + scroll, + scrollBy, + scrollIntoView, + setAttribute, + setPointerCapture, + toggleAttribute, + getAccessKey, setAccessKey, + getClassName, setClassName, + clientHeight, + clientLeft, + clientTop, + clientWidth, + getId, setId, + getInnerHTML, setInnerHTML, + getOuterHTML, setOuterHTML, + scrollHeight, + scrollLeft, + scrollTop, + scrollWidth, + tagName + }; + + function blur(element: HTMLElement) { + element.blur(); + } + + function getAttribute(element: HTMLElement, name: string) { + return element.getAttribute(name); + } + + function getAttributeNames(element: HTMLElement) { + return element.getAttributeNames(); + } + + function getBoundingClientRect(element: HTMLElement) { + return element.getBoundingClientRect(); + } + + function hasAttribute(element: HTMLElement, name: string) { + return element.hasAttribute(name); + } + + function hasAttributes(element: HTMLElement) { + return element.hasAttributes(); + } + + function hasPointerCapture(element: HTMLElement, pointerId: number) { + return element.hasPointerCapture(pointerId); + } + + function matches(element: HTMLElement, selectors: string) { + return element.matches(selectors); + } + + function releasePointerCapture(element: HTMLElement, pointerId: number) { + element.releasePointerCapture(pointerId); + } + + function remove(element: HTMLElement) { + element.remove(); + } + + function removeAttribute(element: HTMLElement, name: string) { + return element.removeAttribute(name); + } + + function requestFullScreen(element: HTMLElement, options?: FullscreenOptions) { + return element.requestFullscreen(options); + } + + function requestPointerLock(element: HTMLElement) { + return element.requestPointerLock(); + } + + function scroll(element: HTMLElement, options?: ScrollToOptions, x?: number, y?: number) { + if (options) { + element.scroll(options); + } else { + element.scroll(x, y); + } + } + + function scrollBy(element: HTMLElement, options?: ScrollToOptions, x?: number, y?: number) { + if (options) { + element.scrollBy(options); + } else { + element.scrollBy(x, y); + } + } + + function scrollIntoView(element: HTMLElement, alignToTop?: boolean, options?: ScrollIntoViewOptions) { + element.scrollIntoView(alignToTop ?? options); + } + + function setAttribute(element: HTMLElement, name: string, value: string) { + return element.setAttribute(name, value); + } + + function setPointerCapture(element: HTMLElement, pointerId: number) { + element.setPointerCapture(pointerId); + } + + function toggleAttribute(element: HTMLElement, name: string, force?: boolean) { + return element.toggleAttribute(name, force); + } + + function getAccessKey(element: HTMLElement) { + return element.accessKey; + } + + function setAccessKey(element: HTMLElement, key: string) { + element.accessKey = key; + } + + function getClassName(element: HTMLElement) { + return element.className; + } + + function setClassName(element: HTMLElement, className: string) { + element.className = className; + } + + function clientHeight(element: HTMLElement) { + return element.clientHeight; + } + + function clientLeft(element: HTMLElement) { + return element.clientLeft; + } + + function clientTop(element: HTMLElement) { + return element.clientTop; + } + + function clientWidth(element: HTMLElement) { + return element.clientWidth; + } + + function getId(element: HTMLElement) { + return element.id; + } + + function setId(element: HTMLElement, id: string) { + element.id = id; + } + + function getInnerHTML(element: HTMLElement) { + return element.innerHTML; + } + + function setInnerHTML(element: HTMLElement, innerHTML: string) { + element.innerHTML = innerHTML; + } + + function getOuterHTML(element: HTMLElement) { + return element.outerHTML; + } + + function setOuterHTML(element: HTMLElement, outerHTML: string) { + element.outerHTML = outerHTML; + } + + function scrollHeight(element: HTMLElement) { + return element.scrollHeight; + } + + function scrollLeft(element: HTMLElement) { + return element.scrollLeft; + } + + function scrollTop(element: HTMLElement) { + return element.scrollTop; + } + + function scrollWidth(element: HTMLElement) { + return element.scrollWidth; + } + + function tagName(element: HTMLElement) { + return element.tagName; + } +}(BitButil)); \ No newline at end of file diff --git a/src/Butil/Bit.Butil/Scripts/events.ts b/src/Butil/Bit.Butil/Scripts/events.ts index 5211f0236c..dda1e543b4 100644 --- a/src/Butil/Bit.Butil/Scripts/events.ts +++ b/src/Butil/Bit.Butil/Scripts/events.ts @@ -24,6 +24,7 @@ var BitButil = BitButil || {}; function removeEventListener(elementName, eventName, dotnetListenerIds, options) { dotnetListenerIds.forEach(id => { const handler = _handlers[id]; + delete _handlers[id]; window[elementName].removeEventListener(eventName, handler, options); }); } diff --git a/src/Butil/Bit.Butil/Scripts/history.ts b/src/Butil/Bit.Butil/Scripts/history.ts new file mode 100644 index 0000000000..4f5606a2b1 --- /dev/null +++ b/src/Butil/Bit.Butil/Scripts/history.ts @@ -0,0 +1,72 @@ +var BitButil = BitButil || {}; + +(function (butil: any) { + const _handlers = {}; + + butil.history = { + length, + scrollRestoration, + setScrollRestoration, + state, + back, + forward, + go, + pushState, + replaceState, + addPopState, + removePopState + }; + + function length() { + return window.history.length; + } + + function scrollRestoration() { + return window.history.scrollRestoration; + } + + function setScrollRestoration(value) { + window.history.scrollRestoration = value; + } + + function state() { + return window.history.state; + } + + function back() { + window.history.back(); + } + + function forward() { + window.history.forward(); + } + + function go(delta) { + window.history.go(delta); + } + + function pushState(state, unused, url) { + window.history.pushState(state, unused, url); + } + + function replaceState(state, unused, url) { + window.history.replaceState(state, unused, url); + } + + function addPopState(methodName, listenerId) { + const handler = e => { + DotNet.invokeMethodAsync('Bit.Butil', methodName, listenerId, e.state); + }; + + _handlers[listenerId] = handler; + window.addEventListener('popstate', handler); + } + + function removePopState(ids) { + ids.forEach(id => { + const handler = _handlers[id]; + delete _handlers[id]; + window.removeEventListener('popstate', handler); + }); + } +}(BitButil)); \ No newline at end of file diff --git a/src/Butil/Bit.Butil/Scripts/keyboard.ts b/src/Butil/Bit.Butil/Scripts/keyboard.ts index 0ad1c20121..57aaaa379f 100644 --- a/src/Butil/Bit.Butil/Scripts/keyboard.ts +++ b/src/Butil/Bit.Butil/Scripts/keyboard.ts @@ -8,9 +8,9 @@ var BitButil = BitButil || {}; remove }; - function add(methodName, listenerId, key, alt, ctrl, meta, shift, preventDefault, stopPropagation, repeat) { + function add(methodName, listenerId, code, alt, ctrl, meta, shift, preventDefault, stopPropagation, repeat) { const handler = e => { - if (e.key !== key) return; + if (e.code !== code) return; if (!alt && e.altKey) return; if (!ctrl && e.ctrlKey) return; @@ -33,6 +33,7 @@ var BitButil = BitButil || {}; function remove(ids) { ids.forEach(id => { const handler = _handlers[id]; + delete _handlers[id]; document.removeEventListener('keydown', handler); }); } diff --git a/src/Butil/Bit.Butil/Scripts/navigator.ts b/src/Butil/Bit.Butil/Scripts/navigator.ts new file mode 100644 index 0000000000..7f3b5162ce --- /dev/null +++ b/src/Butil/Bit.Butil/Scripts/navigator.ts @@ -0,0 +1,81 @@ +var BitButil = BitButil || {}; + +(function (butil: any) { + butil.navigator = { + deviceMemory, + hardwareConcurrency, + language, + languages, + maxTouchPoints, + onLine, + pdfViewerEnabled, + userAgent, + webdriver, + canShare, + clearAppBadge, + sendBeacon, + setAppBadge, + share, + vibrate + }; + + function deviceMemory() { + return (window.navigator as any).deviceMemory; + } + + function hardwareConcurrency() { + return window.navigator.hardwareConcurrency; + } + + function language() { + return window.navigator.language; + } + + function languages() { + return window.navigator.languages; + } + + function maxTouchPoints() { + return window.navigator.maxTouchPoints; + } + + function onLine() { + return window.navigator.onLine; + } + + function pdfViewerEnabled() { + return window.navigator.pdfViewerEnabled; + } + + function userAgent() { + return window.navigator.userAgent; + } + + function webdriver() { + return window.navigator.webdriver; + } + + function canShare() { + return window.navigator.canShare(); + } + + function clearAppBadge() { + return window.navigator.clearAppBadge(); + } + + function sendBeacon(url: string, data) { + return window.navigator.sendBeacon(url, data) + } + + function setAppBadge(contents) { + return window.navigator.setAppBadge(contents); + } + + function share(data) { + return window.navigator.share(data); + } + + function vibrate(pattern) { + return window.navigator.vibrate(pattern); + } +}(BitButil)); \ No newline at end of file diff --git a/src/Butil/README.md b/src/Butil/README.md index c518459607..4e62e6fc54 100644 --- a/src/Butil/README.md +++ b/src/Butil/README.md @@ -1,9 +1,21 @@ -# Butil -Blazor Utilities for JavaScript +# bit Butil +bit Blazor Utilities for JavaScript --- -To start using `Butil` you first need to add its services like this: +To start using `Butil` you first need to install the NuGet package: + +``` +dotnet add package Bit.Butil +``` + +then add its script tag to your app: + +```html + +``` + +you also need to add its services like this: ```csharp using Bit.Butil; @@ -15,7 +27,7 @@ builder.Services.AddBitButilServices(); ... ``` -Then you can inject its classes for each tool. +Now you can inject its classes to use the utilities. ### Console diff --git a/src/SourceGenerators/Bit.SourceGenerators/Bit.SourceGenerators.csproj b/src/SourceGenerators/Bit.SourceGenerators/Bit.SourceGenerators.csproj index 9bb6975907..0a585876fd 100644 --- a/src/SourceGenerators/Bit.SourceGenerators/Bit.SourceGenerators.csproj +++ b/src/SourceGenerators/Bit.SourceGenerators/Bit.SourceGenerators.csproj @@ -4,13 +4,15 @@ netstandard2.0 - 11.0 false true $(PackageTags) Source-Generators + $(GetTargetPathDependsOn);GetDependencyTargetPaths + + @@ -27,4 +29,11 @@ + + + + + + + diff --git a/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/ActionParameter.cs b/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/ActionParameter.cs new file mode 100644 index 0000000000..5e7561332a --- /dev/null +++ b/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/ActionParameter.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.CodeAnalysis; + +namespace Bit.SourceGenerators; + +public class ActionParameter +{ + public string Name { get; set; } = default!; + + public ITypeSymbol Type { get; set; } = default!; +} diff --git a/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/ControllerAction.cs b/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/ControllerAction.cs new file mode 100644 index 0000000000..e2ee654eee --- /dev/null +++ b/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/ControllerAction.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using Microsoft.CodeAnalysis; + +namespace Bit.SourceGenerators; + +public class ControllerAction +{ + public IMethodSymbol Method { get; set; } = default!; + + public ITypeSymbol ReturnType { get; set; } = default!; + + public bool DoesReturnSomething => ReturnType.ToDisplayString() is not "System.Threading.Tasks.Task" or "System.Threading.Tasks.ValueTask"; + + public string HttpMethod { get; set; } = default!; + + public string Url { get; set; } = default!; + + public List Parameters { get; set; } = []; + + public ActionParameter? BodyParameter { get; set; } + + public bool HasCancellationToken { get; set; } +} diff --git a/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/HttpClientProxySourceGenerator.cs b/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/HttpClientProxySourceGenerator.cs new file mode 100644 index 0000000000..4eb6257c8b --- /dev/null +++ b/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/HttpClientProxySourceGenerator.cs @@ -0,0 +1,120 @@ +using System; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; + +namespace Bit.SourceGenerators; + +[Generator] +public class HttpClientProxySourceGenerator : ISourceGenerator +{ + public void Initialize(GeneratorInitializationContext context) + { + context.RegisterForSyntaxNotifications(() => new HttpClientProxySyntaxReceiver()); + } + + public void Execute(GeneratorExecutionContext context) + { + if (context.SyntaxContextReceiver is not HttpClientProxySyntaxReceiver receiver || receiver.IControllers.Any() is false) + { + return; + } + + StringBuilder generatedClasses = new(); + + foreach (var iController in receiver.IControllers) + { + StringBuilder generatedMethods = new(); + + foreach (var action in iController.Actions) + { + string parameters = string.Join(", ", action.Parameters.Select(p => $"{p.Type.ToDisplayString()} {p.Name}")); + + var hasQueryString = action.Url.Contains('?'); + + generatedMethods.AppendLine($@" + public async {action.ReturnType.ToDisplayString()} {action.Method.Name}({parameters}) + {{ + {$@"var url = $""{action.Url}"";"} + var dynamicQS = GetDynamicQueryString(); + if (dynamicQS is not null) + {{ + url += {(action.Url.Contains('?') ? "'&'" : "'?'")} + dynamicQS; + }} + {(action.DoesReturnSomething ? $@"return (await prerenderStateService.GetValue(url, async () => + {{" : string.Empty)} + using var request = new HttpRequestMessage(HttpMethod.{action.HttpMethod}, url); + {(action.BodyParameter is not null ? $@"request.Content = JsonContent.Create({action.BodyParameter.Name}, options.GetTypeInfo<{action.BodyParameter.Type.ToDisplayString()}>());" : string.Empty)} + using var response = await httpClient.SendAsync(request{(action.HasCancellationToken ? ", cancellationToken" : string.Empty)}); + {(action.DoesReturnSomething ? ($"return await response.Content.ReadFromJsonAsync(options.GetTypeInfo<{action.ReturnType.GetUnderlyingType().ToDisplayString()}>(){(action.HasCancellationToken ? ", cancellationToken" : string.Empty)});}}))!;") : string.Empty)} + }} +"); + } + + generatedClasses.AppendLine($@" + internal class {iController.ClassName}(HttpClient httpClient, JsonSerializerOptions options, IPrerenderStateService prerenderStateService) : AppControllerBase, {iController.Symbol.ToDisplayString()} + {{ + {generatedMethods} + }}"); + } + + StringBuilder finalSource = new(@$" +using System.Text.Json; +using System.Web; + +namespace Microsoft.Extensions.DependencyInjection; + +[global::System.CodeDom.Compiler.GeneratedCode(""Bit.SourceGenerators"",""{BitSourceGeneratorUtil.GetPackageVersion()}"")] +[global::System.Diagnostics.DebuggerNonUserCode] +[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +internal static class IHttpClientServiceCollectionExtensions +{{ + public static void AddTypedHttpClients(this IServiceCollection services) + {{ +{string.Join(Environment.NewLine, receiver.IControllers.Select(i => $" services.TryAddTransient<{i.Symbol.ToDisplayString()}, {i.ClassName}>();"))} + }} + + internal class AppControllerBase + {{ + Dictionary queryString = []; + + public void AddQueryString(string key, object? value) + {{ + queryString.Add(key, value); + }} + + public void AddQueryStrings(Dictionary queryString) + {{ + foreach (var key in queryString.Keys) + {{ + AddQueryString(key, queryString[key]); + }} + }} + + protected string? GetDynamicQueryString() + {{ + if (queryString is not {{ Count: > 0 }}) + return null; + + var collection = HttpUtility.ParseQueryString(string.Empty); + + foreach (var key in queryString.Keys) + {{ + collection.Add(key, queryString[key]?.ToString()); + }} + + queryString.Clear(); + + return collection.ToString(); + }} + }} + +{generatedClasses} + +}} +"); + + context.AddSource($"HttpClientProxy.cs", finalSource.ToString()); + } +} diff --git a/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/HttpClientProxySyntaxReceiver.cs b/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/HttpClientProxySyntaxReceiver.cs new file mode 100644 index 0000000000..2026d5cdec --- /dev/null +++ b/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/HttpClientProxySyntaxReceiver.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using System.Linq; +using DoLess.UriTemplates; +using System.Web; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Bit.SourceGenerators; + +public class HttpClientProxySyntaxReceiver : ISyntaxContextReceiver +{ + public List IControllers { get; } = []; + + public void OnVisitSyntaxNode(GeneratorSyntaxContext syntaxNode) + { + if (syntaxNode.Node is InterfaceDeclarationSyntax interfaceDeclarationSyntax + && interfaceDeclarationSyntax.BaseList is not null + && interfaceDeclarationSyntax.BaseList.Types.Any(t => t.Type.ToString() == "IAppController")) + { + var model = syntaxNode.SemanticModel.Compilation.GetSemanticModel(interfaceDeclarationSyntax.SyntaxTree); + var controllerSymbol = (ITypeSymbol)model.GetDeclaredSymbol(interfaceDeclarationSyntax)!; + bool isController = controllerSymbol.IsIController(); + + if (isController == true) + { + var controllerName = controllerSymbol.Name[1..].Replace("Controller", string.Empty); + + var route = controllerSymbol + .GetAttributes() + .FirstOrDefault(a => a.AttributeClass?.Name.StartsWith("Route") is true)? + .ConstructorArguments + .FirstOrDefault() + .Value? + .ToString() + ?.Replace("[controller]", controllerName) ?? string.Empty; + + var actions = controllerSymbol.GetMembers() + .OfType() + .Where(m => m.MethodKind == MethodKind.Ordinary) + .Select(m => new ControllerAction + { + Method = m, + ReturnType = m.ReturnType, + HttpMethod = m.GetHttpMethod(), + Url = m.Name, + Parameters = m.Parameters.Select(y => new ActionParameter + { + Name = y.Name, + Type = y.Type + }).ToList() + }).ToList(); + + foreach (var action in actions) + { + var uriTemplate = UriTemplate.For($"{route}{action.Method.GetAttributes() + .FirstOrDefault(a => a.AttributeClass?.Name.StartsWith("Http") is true)? + .ConstructorArguments.FirstOrDefault().Value?.ToString()}".Replace("[action]", action.Method.Name)); + + foreach (var parameter in action.Parameters) + { + uriTemplate.WithParameter(parameter.Name, $"{{{parameter.Name}}}"); + } + + string url = HttpUtility.UrlDecode(uriTemplate.ExpandToString()); + + // if there is a parameter that is not a cancellation token and is not in the route template, then it is the body parameter + action.BodyParameter = action.Parameters.FirstOrDefault(p => p.Type.ToDisplayString() is not "System.Threading.CancellationToken" && url.Contains($"{{{p.Name}}}") is false); + action.HasCancellationToken = action.Parameters.Any(p => p.Type.ToDisplayString() is "System.Threading.CancellationToken"); + action.Url = url; + } + + IControllers.Add(new IController + { + Actions = actions, + Name = controllerName, + ClassName = controllerSymbol.Name[1..], + Symbol = controllerSymbol, + Syntax = interfaceDeclarationSyntax + }); + } + } + } +} diff --git a/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/IController.cs b/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/IController.cs new file mode 100644 index 0000000000..c6718b6cf4 --- /dev/null +++ b/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/IController.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis; + +namespace Bit.SourceGenerators; + +public class IController +{ + public string Name { get; set; } = default!; + + public string ClassName { get; set; } = default!; + + public ITypeSymbol Symbol { get; set; } = default!; + + public InterfaceDeclarationSyntax Syntax { get; set; } = default!; + + public List Actions { get; set; } = []; +} + diff --git a/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/ITypeSymboExtensions.cs b/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/ITypeSymboExtensions.cs new file mode 100644 index 0000000000..1e32f9bc32 --- /dev/null +++ b/src/SourceGenerators/Bit.SourceGenerators/HttpClientProxy/ITypeSymboExtensions.cs @@ -0,0 +1,33 @@ +using System.Linq; + +namespace Microsoft.CodeAnalysis; + +public static class ITypeSymbolExtensions +{ + public static bool IsIController(this ITypeSymbol type) + { + return type.AllInterfaces.Any(x => x.Name == "IAppController"); + } + + public static string GetHttpMethod(this IMethodSymbol method) + { + return method.GetAttributes().FirstOrDefault(a => a.AttributeClass?.Name.StartsWith("Http") is true)?.AttributeClass?.Name switch + { + "HttpGetAttribute" => "Get", + "HttpPostAttribute" => "Post", + "HttpPutAttribute" => "Put", + "HttpDeleteAttribute" => "Delete", + "HttpPatchAttribute" => "Patch", + _ => "Get" + }; + } + + public static ITypeSymbol GetUnderlyingType(this ITypeSymbol typeSymbol) + { + return typeSymbol switch + { + INamedTypeSymbol namedTypeSymbol => namedTypeSymbol.TypeArguments.FirstOrDefault() ?? namedTypeSymbol, + _ => typeSymbol + }; + } +} diff --git a/src/Templates/BlazorEmpty/Bit.BlazorEmpty/BlazorEmpty.Client/BlazorEmpty.Client.csproj b/src/Templates/BlazorEmpty/Bit.BlazorEmpty/BlazorEmpty.Client/BlazorEmpty.Client.csproj index 368eabe7c8..bdaa4d3a17 100644 --- a/src/Templates/BlazorEmpty/Bit.BlazorEmpty/BlazorEmpty.Client/BlazorEmpty.Client.csproj +++ b/src/Templates/BlazorEmpty/Bit.BlazorEmpty/BlazorEmpty.Client/BlazorEmpty.Client.csproj @@ -1,4 +1,4 @@ - + @@ -15,14 +15,14 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Templates/BlazorEmpty/Bit.BlazorEmpty/BlazorEmpty/BlazorEmpty.csproj b/src/Templates/BlazorEmpty/Bit.BlazorEmpty/BlazorEmpty/BlazorEmpty.csproj index e01d16b824..b23cb716ea 100644 --- a/src/Templates/BlazorEmpty/Bit.BlazorEmpty/BlazorEmpty/BlazorEmpty.csproj +++ b/src/Templates/BlazorEmpty/Bit.BlazorEmpty/BlazorEmpty/BlazorEmpty.csproj @@ -1,4 +1,4 @@ - + @@ -18,14 +18,14 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/.azure-devops/workflows/cd.yml b/src/Templates/Boilerplate/Bit.Boilerplate/.azure-devops/workflows/cd.yml index 68613a4250..0d2c482caa 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/.azure-devops/workflows/cd.yml +++ b/src/Templates/Boilerplate/Bit.Boilerplate/.azure-devops/workflows/cd.yml @@ -8,7 +8,7 @@ variables: AZURE_SUBSCRIPTION: 'bp-test-service-connection' # https://learn.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml#azure-resource-manager-service-connection ConnectionStrings.SqlServerConnectionString: $(DB_CONNECTION_STRING) AppSettings.IdentitySettings.IdentityCertificatePassword: $(API_IDENTITY_CERTIFICATE_PASSWORD) - ApiServerAddress: 'https://bp.bitplatform.dev/api/' + ApiServerAddress: 'https://bp.bitplatform.dev/' jobs: @@ -29,6 +29,13 @@ jobs: inputs: versionSpec: '18.x' displayName: 'Install Node.js' + + # - task: Bash@3 + # displayName: 'Enable pre rendering' + # inputs: + # targetType: 'inline' + # script: | + # 'sed -i 's/public static readonly bool PrerenderEnabled = false;/public static readonly bool PrerenderEnabled = true;/g' src/Client/Boilerplate.Client.Core/Services/AppRenderMode.cs' - task: Bash@3 displayName: 'Install wasm' diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/.github/workflows/cd.yml b/src/Templates/Boilerplate/Bit.Boilerplate/.github/workflows/cd.yml index 149e07b687..a650a70516 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/.github/workflows/cd.yml +++ b/src/Templates/Boilerplate/Bit.Boilerplate/.github/workflows/cd.yml @@ -34,6 +34,9 @@ jobs: - uses: actions/setup-node@v3 with: node-version: 18 + + # - name: Enable pre rendering + # run: sed -i 's/public static readonly bool PrerenderEnabled = false;/public static readonly bool PrerenderEnabled = true;/g' src/Client/Boilerplate.Client.Core/Services/AppRenderMode.cs - name: Update appsettings.json api server address uses: microsoft/variable-substitution@v1 diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/.template.config/template.json b/src/Templates/Boilerplate/Bit.Boilerplate/.template.config/template.json index cfde5227bc..931dcc6871 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/.template.config/template.json +++ b/src/Templates/Boilerplate/Bit.Boilerplate/.template.config/template.json @@ -139,12 +139,16 @@ "src/Shared/Dtos/Products/**", "src/Boilerplate.Server/Controllers/Categories/**", "src/Boilerplate.Server/Controllers/Products/**", + "src/Boilerplate.Server/Controllers/Dashboard/**", "src/Boilerplate.Server/Data/Configurations/Category/**", "src/Boilerplate.Server/Data/Configurations/Product/**", "src/Boilerplate.Server/Mappers/CategoriesMapper.cs", "src/Boilerplate.Server/Mappers/ProductsMapper.cs", "src/Boilerplate.Server/Models/Categories/**", "src/Boilerplate.Server/Models/Products/**", + "src/Client/Boilerplate.Client.Core/Controllers/Categories/**", + "src/Client/Boilerplate.Client.Core/Controllers/Products/**", + "src/Client/Boilerplate.Client.Core/Controllers/Dashboard/**", "src/Client/Boilerplate.Client.Core/Components/Pages/Categories/**", "src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/**", "src/Client/Boilerplate.Client.Core/Components/Pages/Products/**"] @@ -155,6 +159,7 @@ "src/Boilerplate.Server/Controllers/Todo/**", "src/Boilerplate.Server/Mappers/TodoMapper.cs", "src/Boilerplate.Server/Models/Todo/**", + "src/Client/Boilerplate.Client.Core/Controllers/Todo/**", "src/Client/Boilerplate.Client.Core/Components/Pages/Todo/**"] } ] diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/Boilerplate.Web.slnf b/src/Templates/Boilerplate/Bit.Boilerplate/Boilerplate.Web.slnf new file mode 100644 index 0000000000..aa4b869889 --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/Boilerplate.Web.slnf @@ -0,0 +1,11 @@ +{ + "solution": { + "path": "Boilerplate.sln", + "projects": [ + "src\\Boilerplate.Server\\Boilerplate.Server.csproj", + "src\\Boilerplate.Shared\\Boilerplate.Shared.csproj", + "src\\Client\\Boilerplate.Client.Core\\Boilerplate.Client.Core.csproj", + "src\\Client\\Boilerplate.Client.Web\\Boilerplate.Client.Web.csproj" + ] + } +} \ No newline at end of file diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/AppSettings.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/AppSettings.cs index 52a8dad91b..5c5e31a400 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/AppSettings.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/AppSettings.cs @@ -9,8 +9,6 @@ public class AppSettings public HealthCheckSettings HealthCheckSettings { get; set; } = default!; public string UserProfileImagesDir { get; set; } = default!; - - public string WebServerAddress { get; set; } = default!; } public class HealthCheckSettings diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Boilerplate.Server.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Boilerplate.Server.csproj index 801495e5be..bd47cf6ede 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Boilerplate.Server.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Boilerplate.Server.csproj @@ -6,11 +6,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -64,7 +64,6 @@ - diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/App.razor b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/App.razor index 12fd1a111f..5ce7095268 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/App.razor +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/App.razor @@ -24,7 +24,7 @@ } - + diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/EmailConfirmationTemplate.razor b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/EmailConfirmationTemplate.razor index ce1c3acefa..5f2cc0f2f9 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/EmailConfirmationTemplate.razor +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/EmailConfirmationTemplate.razor @@ -1,4 +1,7 @@ -@code { +@using Boilerplate.Server.Models.Emailing +@using Boilerplate.Server.Resources + +@code { [Parameter] public EmailConfirmationModel Model { get; set; } = default!; [Parameter] public HttpContext HttpContext { get; set; } = default!; [Inject] public IStringLocalizer EmailLocalizer { get; set; } = default!; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/ResetPasswordTemplate.razor b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/ResetPasswordTemplate.razor index 2a3be2aee5..a4ac208049 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/ResetPasswordTemplate.razor +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/ResetPasswordTemplate.razor @@ -1,3 +1,6 @@ +@using Boilerplate.Server.Models.Emailing +@using Boilerplate.Server.Resources + @code { [Parameter] public ResetPasswordModel Model { get; set; } = default!; [Parameter] public HttpContext HttpContext { get; set; } = default!; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/Script.razor b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/Script.razor index 9cdcddcd48..9394c9f44c 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/Script.razor +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Components/Script.razor @@ -4,15 +4,25 @@ @code { [Parameter] public bool AppendVersion { get; set; } = true; - [Parameter] public required string Src { get; set; } = ""; + [Parameter] public string? Src { get; set; } + [Parameter] public RenderFragment? ChildContent { get; set; } [Parameter(CaptureUnmatchedValues = true)] public Dictionary AdditionalAttributes { get; set; } = default!; - private string src = ""; + private string? src; protected override void OnInitialized() { - src = AppendVersion ? _fileVersionProvider.AddFileVersionToPath(_httpContextAccessor.HttpContext!.Request.PathBase, Src) : Src; + src = (Src is not null && AppendVersion) ? _fileVersionProvider.AddFileVersionToPath(_httpContextAccessor.HttpContext!.Request.PathBase, Src) : Src; } } - \ No newline at end of file +@if (src is not null) +{ + +} +else +{ + +} \ No newline at end of file diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Categories/CategoryController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Categories/CategoryController.cs index c7e82e8e31..d8a538c5f1 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Categories/CategoryController.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Categories/CategoryController.cs @@ -1,11 +1,12 @@ -using Boilerplate.Server.Models.Categories; +using Boilerplate.Client.Core.Controllers.Categories; +using Boilerplate.Server.Models.Categories; using Boilerplate.Shared.Dtos.Categories; namespace Boilerplate.Server.Controllers; [Route("api/[controller]/[action]")] [ApiController] -public partial class CategoryController : AppControllerBase +public partial class CategoryController : AppControllerBase, ICategoryController { [HttpGet, EnableQuery] public IQueryable Get() @@ -14,17 +15,6 @@ public IQueryable Get() .Project(); } - [HttpGet("{id:int}")] - public async Task Get(int id, CancellationToken cancellationToken) - { - var category = await Get().FirstOrDefaultAsync(t => t.Id == id, cancellationToken); - - if (category is null) - throw new ResourceNotFoundException(Localizer[nameof(AppStrings.CategoryCouldNotBeFound)]); - - return category; - } - [HttpGet] public async Task> GetCategories(ODataQueryOptions odataQuery, CancellationToken cancellationToken) { @@ -41,6 +31,17 @@ public async Task> GetCategories(ODataQueryOptions(query.AsAsyncEnumerable(), totalCount); } + [HttpGet("{id}")] + public async Task Get(int id, CancellationToken cancellationToken) + { + var category = await Get().FirstOrDefaultAsync(t => t.Id == id, cancellationToken); + + if (category is null) + throw new ResourceNotFoundException(Localizer[nameof(AppStrings.CategoryCouldNotBeFound)]); + + return category; + } + [HttpPost] public async Task Create(CategoryDto dto, CancellationToken cancellationToken) { @@ -68,7 +69,7 @@ public async Task Update(CategoryDto dto, CancellationToken cancell return categoryToUpdate.Map(); } - [HttpDelete("{id:int}")] + [HttpDelete("{id}")] public async Task Delete(int id, CancellationToken cancellationToken) { if (await DbContext.Products.AnyAsync(p => p.CategoryId == id, cancellationToken)) diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Products/DashboardController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Dashboard/DashboardController.cs similarity index 82% rename from src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Products/DashboardController.cs rename to src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Dashboard/DashboardController.cs index f8466c2f6b..9cf2562471 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Products/DashboardController.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Dashboard/DashboardController.cs @@ -1,27 +1,28 @@ using Boilerplate.Shared.Dtos.Dashboard; +using Boilerplate.Client.Core.Controllers.Dashboard; namespace Boilerplate.Server.Controllers; [Route("api/[controller]/[action]")] [ApiController] -public partial class DashboardController : AppControllerBase +public partial class DashboardController : AppControllerBase, IDashboardController { [HttpGet] - public async Task GetOverallAnalyticsStatsData() + public async Task GetOverallAnalyticsStatsData(CancellationToken cancellationToken) { var result = new OverallAnalyticsStatsDataResponseDto(); var last30DaysDate = DateTimeOffset.UtcNow.AddDays(-30); - result.TotalProducts = await DbContext.Products.CountAsync(); - result.Last30DaysProductCount = await DbContext.Products.CountAsync(p => p.CreatedOn > last30DaysDate); - result.TotalCategories = await DbContext.Categories.CountAsync(); + result.TotalProducts = await DbContext.Products.CountAsync(cancellationToken); + result.Last30DaysProductCount = await DbContext.Products.CountAsync(p => p.CreatedOn > last30DaysDate, cancellationToken); + result.TotalCategories = await DbContext.Categories.CountAsync(cancellationToken); return result; } [HttpGet] - public async Task> GetProductsCountPerCategotyStats() + public async Task> GetProductsCountPerCategoryStats(CancellationToken cancellationToken) { return DbContext.Categories .Select(c => new ProductsCountPerCategoryResponseDto() @@ -33,7 +34,7 @@ public async Task> GetProd } [HttpGet] - public async Task> GetProductsSalesStats() + public async Task> GetProductsSalesStats(CancellationToken cancellationToken) { Random rand = new Random(); return DbContext.Products.Include(p => p.Category) diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Identity/IdentityController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Identity/IdentityController.cs index 98a3d36c28..fcbffc45ea 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Identity/IdentityController.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Identity/IdentityController.cs @@ -1,5 +1,6 @@ //-:cnd:noEmit using System.Web; +using Boilerplate.Client.Core.Controllers.Identity; using Boilerplate.Server.Components; using Boilerplate.Server.Models.Emailing; using Boilerplate.Server.Models.Identity; @@ -14,7 +15,7 @@ namespace Boilerplate.Server.Controllers.Identity; [Microsoft.AspNetCore.Mvc.Route("api/[controller]/[action]")] [ApiController, AllowAnonymous] -public partial class IdentityController : AppControllerBase +public partial class IdentityController : AppControllerBase, IIdentityController { [AutoInject] private UserManager userManager = default!; @@ -151,7 +152,7 @@ public async Task ConfirmEmail(string email, string token) return Redirect(url); } - [HttpPost] + [HttpPost, ProducesResponseType(statusCode: 200)] public async Task SignIn(SignInRequestDto signInRequest) { signInManager.AuthenticationScheme = IdentityConstants.BearerScheme; @@ -247,7 +248,7 @@ public async Task SendResetPasswordEmail(SendResetPasswordEmailRequestDto sendRe } [HttpPost] - public async Task ResetPassword(ResetPasswordRequestDto resetPasswordRequest) + public async Task ResetPassword(ResetPasswordRequestDto resetPasswordRequest, CancellationToken cancellationToken) { var user = await userManager.FindByEmailAsync(resetPasswordRequest.Email!); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Identity/UserController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Identity/UserController.cs index e18e31091b..afddb1c038 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Identity/UserController.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Identity/UserController.cs @@ -1,11 +1,12 @@ -using Boilerplate.Server.Models.Identity; +using Boilerplate.Client.Core.Controllers.Identity; +using Boilerplate.Server.Models.Identity; using Boilerplate.Shared.Dtos.Identity; namespace Boilerplate.Server.Controllers.Identity; [Route("api/[controller]/[action]")] [ApiController] -public partial class UserController : AppControllerBase +public partial class UserController : AppControllerBase, IUserController { [AutoInject] private UserManager userManager = default!; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Products/ProductController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Products/ProductController.cs index 02ac1ac2bd..d50fa46b42 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Products/ProductController.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Products/ProductController.cs @@ -1,11 +1,12 @@ -using Boilerplate.Server.Models.Products; +using Boilerplate.Client.Core.Controllers.Product; +using Boilerplate.Server.Models.Products; using Boilerplate.Shared.Dtos.Products; namespace Boilerplate.Server.Controllers; [Route("api/[controller]/[action]")] [ApiController] -public partial class ProductController : AppControllerBase +public partial class ProductController : AppControllerBase, IProductController { [HttpGet, EnableQuery] public IQueryable Get() @@ -14,17 +15,6 @@ public IQueryable Get() .Project(); } - [HttpGet("{id:int}")] - public async Task Get(int id, CancellationToken cancellationToken) - { - var product = await Get().FirstOrDefaultAsync(t => t.Id == id, cancellationToken); - - if (product is null) - throw new ResourceNotFoundException(Localizer[nameof(AppStrings.ProductCouldNotBeFound)]); - - return product; - } - [HttpGet] public async Task> GetProducts(ODataQueryOptions odataQuery, CancellationToken cancellationToken) { @@ -41,6 +31,17 @@ public async Task> GetProducts(ODataQueryOptions(query.AsAsyncEnumerable(), totalCount); } + [HttpGet("{id}")] + public async Task Get(int id, CancellationToken cancellationToken) + { + var product = await Get().FirstOrDefaultAsync(t => t.Id == id, cancellationToken); + + if (product is null) + throw new ResourceNotFoundException(Localizer[nameof(AppStrings.ProductCouldNotBeFound)]); + + return product; + } + [HttpPost] public async Task Create(ProductDto dto, CancellationToken cancellationToken) { @@ -68,7 +69,7 @@ public async Task Update(ProductDto dto, CancellationToken cancellat return productToUpdate.Map(); } - [HttpDelete("{id:int}")] + [HttpDelete("{id}")] public async Task Delete(int id, CancellationToken cancellationToken) { DbContext.Remove(new Product { Id = id }); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Todo/TodoItemController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Todo/TodoItemController.cs index bf3d88bf27..65173823c5 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Todo/TodoItemController.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Controllers/Todo/TodoItemController.cs @@ -1,11 +1,12 @@ -using Boilerplate.Server.Models.Todo; +using Boilerplate.Client.Core.Controllers.Todo; +using Boilerplate.Server.Models.Todo; using Boilerplate.Shared.Dtos.Todo; namespace Boilerplate.Server.Controllers.Todo; [Route("api/[controller]/[action]")] [ApiController] -public partial class TodoItemController : AppControllerBase +public partial class TodoItemController : AppControllerBase, ITodoItemController { [HttpGet, EnableQuery] public IQueryable Get() @@ -17,17 +18,6 @@ public IQueryable Get() .Project(); } - [HttpGet("{id:int}")] - public async Task Get(int id, CancellationToken cancellationToken) - { - var todoItem = await Get().FirstOrDefaultAsync(t => t.Id == id, cancellationToken); - - if (todoItem is null) - throw new ResourceNotFoundException(Localizer[nameof(AppStrings.ToDoItemCouldNotBeFound)]); - - return todoItem; - } - [HttpGet] public async Task> GetTodoItems(ODataQueryOptions odataQuery, CancellationToken cancellationToken) { @@ -44,6 +34,17 @@ public async Task> GetTodoItems(ODataQueryOptions(query.AsAsyncEnumerable(), totalCount); } + [HttpGet("{id}")] + public async Task Get(int id, CancellationToken cancellationToken) + { + var todoItem = await Get().FirstOrDefaultAsync(t => t.Id == id, cancellationToken); + + if (todoItem is null) + throw new ResourceNotFoundException(Localizer[nameof(AppStrings.ToDoItemCouldNotBeFound)]); + + return todoItem; + } + [HttpPost] public async Task Create(TodoItemDto dto, CancellationToken cancellationToken) { @@ -75,7 +76,7 @@ public async Task Update(TodoItemDto dto, CancellationToken cancell return todoItemToUpdate.Map(); } - [HttpDelete("{id:int}")] + [HttpDelete("{id}")] public async Task Delete(int id, CancellationToken cancellationToken) { DbContext.Remove(new TodoItem { Id = id }); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Extensions/IServiceCollectionExtensions.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Extensions/IServiceCollectionExtensions.cs index a93cf3cc35..ca30902e34 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Extensions/IServiceCollectionExtensions.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Extensions/IServiceCollectionExtensions.cs @@ -1,6 +1,4 @@ -using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; -using Boilerplate.Client.Core.Services.HttpMessageHandlers; using Boilerplate.Server; using Boilerplate.Server.Models.Identity; using Boilerplate.Server.Services; @@ -26,7 +24,7 @@ public static void AddBlazor(this IServiceCollection services, IConfiguration co apiServerAddress = new Uri(sp.GetRequiredService().HttpContext!.Request.GetBaseUrl(), apiServerAddress); } - return new HttpClient(sp.GetRequiredService()) + return new HttpClient(sp.GetRequiredKeyedService("DefaultMessageHandler")) { BaseAddress = apiServerAddress }; @@ -47,10 +45,11 @@ public static void AddIdentity(this IServiceCollection services, IConfiguration var settings = appSettings.IdentitySettings; var certificatePath = Path.Combine(Directory.GetCurrentDirectory(), "IdentityCertificate.pfx"); + var certificate = new X509Certificate2(certificatePath, appSettings.IdentitySettings.IdentityCertificatePassword, OperatingSystem.IsWindows() ? X509KeyStorageFlags.EphemeralKeySet : X509KeyStorageFlags.DefaultKeySet); services.AddDataProtection() .PersistKeysToDbContext() - .ProtectKeysWithCertificate(new X509Certificate2(certificatePath, appSettings.IdentitySettings.IdentityCertificatePassword, OperatingSystem.IsWindows() ? X509KeyStorageFlags.EphemeralKeySet : X509KeyStorageFlags.DefaultKeySet)); + .ProtectKeysWithCertificate(certificate); services.AddIdentity(options => { @@ -78,20 +77,13 @@ public static void AddIdentity(this IServiceCollection services, IConfiguration options.BearerTokenExpiration = settings.BearerTokenExpiration; options.RefreshTokenExpiration = settings.RefreshTokenExpiration; - var certificatePath = Path.Combine(Directory.GetCurrentDirectory(), "IdentityCertificate.pfx"); - RSA? rsaPrivateKey; - using (X509Certificate2 signingCert = new X509Certificate2(certificatePath, appSettings.IdentitySettings.IdentityCertificatePassword, OperatingSystem.IsWindows() ? X509KeyStorageFlags.EphemeralKeySet : X509KeyStorageFlags.DefaultKeySet)) - { - rsaPrivateKey = signingCert.GetRSAPrivateKey(); - } - var validationParameters = new TokenValidationParameters { ClockSkew = TimeSpan.Zero, RequireSignedTokens = true, ValidateIssuerSigningKey = true, - IssuerSigningKey = new RsaSecurityKey(rsaPrivateKey), + IssuerSigningKey = new X509SecurityKey(certificate), RequireExpirationTime = true, ValidateLifetime = true, diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Services/AppSecureJwtDataFormat.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Services/AppSecureJwtDataFormat.cs index 7b0f0853b1..e6c8cd146a 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Services/AppSecureJwtDataFormat.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Services/AppSecureJwtDataFormat.cs @@ -17,6 +17,11 @@ public class AppSecureJwtDataFormat(AppSettings appSettings, TokenValidationPara { try { + if (string.IsNullOrEmpty(protectedText)) + { + return NotSignedIn(); + } + var handler = new JwtSecurityTokenHandler(); ClaimsPrincipal? principal = handler.ValidateToken(protectedText, validationParameters, out var validToken); var validJwt = (JwtSecurityToken)validToken; @@ -26,9 +31,9 @@ public class AppSecureJwtDataFormat(AppSettings appSettings, TokenValidationPara }, IdentityConstants.BearerScheme); return data; } - catch + catch (Exception exp) { - return NotSignedIn(); + throw new UnauthorizedException(nameof(AppStrings.UnauthorizedException), exp); } } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Services/ServerExceptionHandler.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Services/ServerExceptionHandler.cs index 262e73764d..728e6a9578 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Services/ServerExceptionHandler.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Services/ServerExceptionHandler.cs @@ -1,5 +1,6 @@ using System.Net; using System.Reflection; +using System.Text.Json; using Microsoft.AspNetCore.Diagnostics; using Microsoft.Net.Http.Headers; @@ -9,6 +10,7 @@ public partial class ServerExceptionHandler : IExceptionHandler { [AutoInject] private IWebHostEnvironment webHostEnvironment = default!; [AutoInject] private IStringLocalizer localizer = default!; + [AutoInject] private JsonSerializerOptions jsonSerializerOptions = default!; public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e, CancellationToken cancellationToken) { @@ -43,7 +45,7 @@ public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e httpContext.Response.StatusCode = statusCode; - await httpContext.Response.WriteAsJsonAsync(restExceptionPayload, AppJsonContext.Default.RestErrorInfo, cancellationToken: cancellationToken); + await httpContext.Response.WriteAsJsonAsync(restExceptionPayload, jsonSerializerOptions.GetTypeInfo(), cancellationToken: cancellationToken); return true; } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Services/ServerSideAuthTokenProvider.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Services/ServerSideAuthTokenProvider.cs index 07ec4e81c1..a89a41a0c0 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Services/ServerSideAuthTokenProvider.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Services/ServerSideAuthTokenProvider.cs @@ -1,7 +1,7 @@ //-:cnd:noEmit using System.Reflection; -using Boilerplate.Client.Core.Services; using Microsoft.JSInterop; +using Boilerplate.Client.Core.Services; namespace Boilerplate.Server.Services; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Startup/Middlewares.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Startup/Middlewares.cs index 7129c73702..b78fd0839c 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Startup/Middlewares.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Startup/Middlewares.cs @@ -2,6 +2,8 @@ using System.Net; using System.Reflection; using System.Runtime.Loader; +using System.Web; +using Boilerplate.Client.Core.Services; using Boilerplate.Server.Components; using HealthChecks.UI.Client; using Microsoft.AspNetCore.Components.Endpoints; @@ -12,10 +14,26 @@ namespace Boilerplate.Server.Startup; public class Middlewares { + /// + /// https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0#middleware-order + /// public static void Use(WebApplication app, IHostEnvironment env, IConfiguration configuration) { app.UseForwardedHeaders(); + if (AppRenderMode.MultilingualEnabled) + { + var supportedCultures = CultureInfoManager.SupportedCultures.Select(sc => CultureInfoManager.CreateCultureInfo(sc.code)).ToArray(); + app.UseRequestLocalization(new RequestLocalizationOptions + { + SupportedCultures = supportedCultures, + SupportedUICultures = supportedCultures, + ApplyCurrentCultureToResponseHeaders = true + }.SetDefaultCulture(CultureInfoManager.DefaultCulture.code)); + } + + app.UseExceptionHandler("/", createScopeForErrors: true); + if (env.IsDevelopment()) { app.UseWebAssemblyDebugging(); @@ -23,7 +41,6 @@ public static void Use(WebApplication app, IHostEnvironment env, IConfiguration else { app.UseHttpsRedirection(); - app.UseResponseCompression(); } Configure_401_403_404_Pages(app); @@ -44,22 +61,17 @@ public static void Use(WebApplication app, IHostEnvironment env, IConfiguration app.UseCors(options => options.WithOrigins("https://0.0.0.0" /*BlazorHybrid*/, "app://0.0.0.0" /*BlazorHybrid*/) .AllowAnyHeader().AllowAnyMethod()); - app.UseResponseCaching(); app.UseAuthentication(); app.UseAuthorization(); - app.UseAntiforgery(); -#if MultilingualEnabled - var supportedCultures = CultureInfoManager.SupportedCultures.Select(sc => CultureInfoManager.CreateCultureInfo(sc.code)).ToArray(); - app.UseRequestLocalization(new RequestLocalizationOptions + if (env.IsDevelopment() is false) { - SupportedCultures = supportedCultures, - SupportedUICultures = supportedCultures, - ApplyCurrentCultureToResponseHeaders = true - }.SetDefaultCulture(CultureInfoManager.DefaultCulture.code)); -#endif + app.UseResponseCompression(); + } - app.UseExceptionHandler("/", createScopeForErrors: true); + app.UseResponseCaching(); + + app.UseAntiforgery(); app.UseSwagger(); @@ -68,6 +80,12 @@ public static void Use(WebApplication app, IHostEnvironment env, IConfiguration options.InjectJavascript($"/swagger/swagger-utils.js?v={Environment.TickCount64}"); }); + app.MapGet("/api/minimal-api-sample/{routeParameter}", (string routeParameter, [FromQuery] string queryStringParameter) => new + { + RouteParameter = routeParameter, + QueryStringParameter = queryStringParameter + }).WithTags("Test"); + app.MapControllers().RequireAuthorization(); var appSettings = configuration.GetSection(nameof(AppSettings)).Get()!; @@ -83,17 +101,22 @@ public static void Use(WebApplication app, IHostEnvironment env, IConfiguration app.MapHealthChecksUI(options => { - options.UseRelativeApiPath = - options.UseRelativeResourcesPath = + options.UseRelativeApiPath = + options.UseRelativeResourcesPath = options.UseRelativeWebhookPath = false; }); } // Handle the rest of requests with blazor - app.MapRazorComponents() + var blazorApp = app.MapRazorComponents() .AddInteractiveServerRenderMode() .AddInteractiveWebAssemblyRenderMode() .AddAdditionalAssemblies(AssemblyLoadContext.Default.Assemblies.Where(asm => asm.GetName().Name?.Contains("Boilerplate") is true).Except([Assembly.GetExecutingAssembly()]).ToArray()); + + if (AppRenderMode.PrerenderEnabled is false) + { + blazorApp.AllowAnonymous(); // Server may not check authorization for pages when there's no pre rendering, let the client handle it. + } } /// @@ -134,7 +157,10 @@ private static void Configure_401_403_404_Pages(WebApplication app) { bool is403 = httpContext.Response.StatusCode is 403; - httpContext.Response.Redirect($"/not-authorized?redirect-url={httpContext.Request.GetEncodedPathAndQuery()}&isForbidden={(is403 ? "true" : "false")}"); + var qs = HttpUtility.ParseQueryString(httpContext.Request.QueryString.Value ?? string.Empty); + qs.Remove("try_refreshing_token"); + var redirectUrl = UriHelper.BuildRelative(httpContext.Request.PathBase, httpContext.Request.Path, new QueryString(qs.ToString())); + httpContext.Response.Redirect($"/not-authorized?redirect-url={redirectUrl}&isForbidden={(is403 ? "true" : "false")}"); } else if (httpContext.Response.StatusCode is 404 && httpContext.GetEndpoint() is null /* Please be aware that certain endpoints, particularly those associated with web API actions, may intentionally return a 404 error. */) diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Startup/Services.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Startup/Services.cs index 90e2c1ac84..d59f6fb351 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Startup/Services.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Server/Startup/Services.cs @@ -22,8 +22,6 @@ public static void Add(IServiceCollection services, IWebHostEnvironment env, ICo services.AddBlazor(configuration); - services.AddClientSharedServices(); - //+:cnd:noEmit services.AddCors(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Boilerplate.Shared.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Boilerplate.Shared.csproj index 3089149225..0c5991e34d 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Boilerplate.Shared.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Boilerplate.Shared.csproj @@ -5,11 +5,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -17,6 +17,7 @@ + compile; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Exceptions/ConflictException.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Exceptions/ConflictException.cs index a4e4239163..88f0794e91 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Exceptions/ConflictException.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Exceptions/ConflictException.cs @@ -5,7 +5,7 @@ namespace Boilerplate.Shared.Exceptions; public class ConflictException : RestException { public ConflictException() - : this(nameof(AppStrings.ConflicException)) + : this(nameof(AppStrings.ConflictException)) { } diff --git a/src/BlazorUI/Demo/Client/Core/Extensions/IConfigurationExtensions.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Extensions/IConfigurationExtensions.cs similarity index 93% rename from src/BlazorUI/Demo/Client/Core/Extensions/IConfigurationExtensions.cs rename to src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Extensions/IConfigurationExtensions.cs index e88b29bed5..a5889120c7 100644 --- a/src/BlazorUI/Demo/Client/Core/Extensions/IConfigurationExtensions.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Extensions/IConfigurationExtensions.cs @@ -4,7 +4,7 @@ public static class IConfigurationExtensions { public static string GetApiServerAddress(this IConfiguration configuration) { - var apiServerAddress = configuration.GetValue("ApiServerAddress", defaultValue: "api/")!; + var apiServerAddress = configuration.GetValue("ApiServerAddress", defaultValue: "/")!; return Uri.TryCreate(apiServerAddress, UriKind.RelativeOrAbsolute, out _) ? apiServerAddress : throw new InvalidOperationException($"Api server address {apiServerAddress} is invalid"); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Extensions/IServiceCollectionExtensions.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Extensions/IServiceCollectionExtensions.cs index 8fceeb61a4..469353e36b 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Extensions/IServiceCollectionExtensions.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Extensions/IServiceCollectionExtensions.cs @@ -1,12 +1,10 @@ -using Boilerplate.Shared.Services; - -namespace Microsoft.Extensions.DependencyInjection; +namespace Microsoft.Extensions.DependencyInjection; public static class IServiceCollectionExtensions { public static IServiceCollection AddSharedServices(this IServiceCollection services) { - // Services being registered here can get injected everywhere (Api, Web, Android, iOS, Windows, macOS and Linux) + // Services being registered here can get injected everywhere (Api, Web, Android, iOS, Windows and macOS) services.TryAddTransient(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Extensions/JsonSeralizerExtensions.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Extensions/JsonSeralizerExtensions.cs new file mode 100644 index 0000000000..c41706ab29 --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Extensions/JsonSeralizerExtensions.cs @@ -0,0 +1,19 @@ +using System.Text.Json.Serialization.Metadata; + +namespace System.Text.Json; + +public static class JsonSerializerOptionsExtensions +{ + /// + /// https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/ + /// + public static JsonTypeInfo GetTypeInfo(this JsonSerializerOptions options) + { + if (options.TryGetTypeInfo(typeof(T), out var result)) + { + return (JsonTypeInfo)result; + } + + return JsonTypeInfo.CreateJsonTypeInfo(options); + } +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Mapper.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Mapper.cs index 50992d64bd..7eb633feb1 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Mapper.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Mapper.cs @@ -23,4 +23,6 @@ public static partial class Mapper public static partial void Patch(this TodoItemDto source, TodoItemDto destination); //#endif public static partial void Patch(this UserDto source, UserDto destination); + public static partial void Patch(this EditUserDto source, UserDto destination); + public static partial void Patch(this UserDto source, EditUserDto destination); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Resources/AppStrings.Designer.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Resources/AppStrings.Designer.cs index b3e1a4aa32..07e6022a48 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Resources/AppStrings.Designer.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Resources/AppStrings.Designer.cs @@ -307,9 +307,10 @@ public static string ConfirmNewPassword { /// /// Looks up a localized string similar to Request could not be processed because of conflict in the request. /// - public static string ConflicException { + public static string ConflictException + { get { - return ResourceManager.GetString("ConflicException", resourceCulture); + return ResourceManager.GetString("ConflictException", resourceCulture); } } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Resources/AppStrings.fr.resx b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Resources/AppStrings.fr.resx index 510cf0fee2..5ceae01417 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Resources/AppStrings.fr.resx +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Resources/AppStrings.fr.resx @@ -147,7 +147,7 @@ Requête invalide - + La demande n'a pas pu être traitée en raison d'un conflit dans la demande diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Resources/AppStrings.resx b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Resources/AppStrings.resx index 4d903f08e0..f354364ea8 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Resources/AppStrings.resx +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Resources/AppStrings.resx @@ -141,7 +141,7 @@ Invalid request - + Request could not be processed because of conflict in the request diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Infra/BuildConfiguration.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Services/BuildConfiguration.cs similarity index 88% rename from src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Infra/BuildConfiguration.cs rename to src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Services/BuildConfiguration.cs index a9998fa892..26b0d55a63 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Infra/BuildConfiguration.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Services/BuildConfiguration.cs @@ -1,5 +1,5 @@ //-:cnd:noEmit -namespace Boilerplate.Shared.Infra; +namespace Boilerplate.Shared.Services; public static class BuildConfiguration { diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Infra/CultureInfoManager.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Services/CultureInfoManager.cs similarity index 98% rename from src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Infra/CultureInfoManager.cs rename to src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Services/CultureInfoManager.cs index e49ab8b769..46c0fd4e28 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Infra/CultureInfoManager.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Boilerplate.Shared/Services/CultureInfoManager.cs @@ -1,4 +1,4 @@ -namespace Boilerplate.Shared.Infra; +namespace Boilerplate.Shared.Services; public class CultureInfoManager { public static (string name, string code) DefaultCulture { get; } = ("English", "en-US"); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Boilerplate.Client.Core.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Boilerplate.Client.Core.csproj index 012c0875ac..6dbeadbc1c 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Boilerplate.Client.Core.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Boilerplate.Client.Core.csproj @@ -16,24 +16,23 @@ - - - + + + - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/NavMenu.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/NavMenu.razor.cs index 91afeb4d18..65b02cb295 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/NavMenu.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/NavMenu.razor.cs @@ -1,10 +1,13 @@ //+:cnd:noEmit +using Boilerplate.Client.Core.Controllers.Identity; using Boilerplate.Shared.Dtos.Identity; namespace Boilerplate.Client.Core.Components.Layout; public partial class NavMenu : IDisposable { + [AutoInject] IUserController userController = default!; + private bool disposed; private bool isSignOutModalOpen; private string? profileImageUrl; @@ -84,11 +87,10 @@ protected override async Task OnInitAsync() StateHasChanged(); }); - user = await PrerenderStateService.GetValue($"{nameof(NavMenu)}-{nameof(user)}", async () => - await HttpClient.GetFromJsonAsync("User/GetCurrentUser", AppJsonContext.Default.UserDto, CurrentCancellationToken)) ?? new(); + user = await userController.GetCurrentUser(CurrentCancellationToken); - var access_token = await PrerenderStateService.GetValue($"{nameof(NavMenu)}-access_token", AuthTokenProvider.GetAccessTokenAsync); - profileImageUrlBase = $"{Configuration.GetApiServerAddress()}Attachment/GetProfileImage?access_token={access_token}&file="; + var access_token = await PrerenderStateService.GetValue(AuthTokenProvider.GetAccessTokenAsync); + profileImageUrlBase = $"{Configuration.GetApiServerAddress()}api/Attachment/GetProfileImage?access_token={access_token}&file="; SetProfileImageUrl(); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Categories/AddOrEditCategoryPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Categories/AddOrEditCategoryPage.razor.cs index 5472dcfce6..4e69e53301 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Categories/AddOrEditCategoryPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Categories/AddOrEditCategoryPage.razor.cs @@ -1,10 +1,13 @@ -using Boilerplate.Shared.Dtos.Categories; +using Boilerplate.Client.Core.Controllers.Categories; +using Boilerplate.Shared.Dtos.Categories; namespace Boilerplate.Client.Core.Components.Pages.Categories; [Authorize] public partial class AddOrEditCategoryPage { + [AutoInject] ICategoryController categoryController = default!; + [Parameter] public int? Id { get; set; } private bool isLoading; @@ -27,7 +30,7 @@ private async Task LoadCategory() try { - category = await HttpClient.GetFromJsonAsync($"Category/Get/{Id}", AppJsonContext.Default.CategoryDto, CurrentCancellationToken) ?? new(); + category = await categoryController.Get(Id.Value, CurrentCancellationToken); } finally { @@ -55,11 +58,11 @@ private async Task Save() { if (category.Id == 0) { - await HttpClient.PostAsJsonAsync("Category/Create", category, AppJsonContext.Default.CategoryDto, CurrentCancellationToken); + await categoryController.Create(category, CurrentCancellationToken); } else { - await HttpClient.PutAsJsonAsync("Category/Update", category, AppJsonContext.Default.CategoryDto, CurrentCancellationToken); + await categoryController.Update(category, CurrentCancellationToken); } NavigationManager.NavigateTo("categories"); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Categories/CategoriesPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Categories/CategoriesPage.razor.cs index b8cbe160a3..ae8defafbf 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Categories/CategoriesPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Categories/CategoriesPage.razor.cs @@ -1,4 +1,5 @@ //-:cnd:noEmit +using Boilerplate.Client.Core.Controllers.Categories; using Boilerplate.Shared.Dtos.Categories; namespace Boilerplate.Client.Core.Components.Pages.Categories; @@ -6,6 +7,8 @@ namespace Boilerplate.Client.Core.Components.Pages.Categories; [Authorize] public partial class CategoriesPage { + [AutoInject] ICategoryController categoryController = default!; + private bool isLoading; private string categoryNameFilter = string.Empty; @@ -40,25 +43,24 @@ private void PrepareGridDataProvider() try { // https://docs.microsoft.com/en-us/odata/concepts/queryoptions-overview - var query = new Dictionary() + + categoryController.AddQueryStrings(new() { { "$top", req.Count ?? 10 }, { "$skip", req.StartIndex } - }; + }); if (string.IsNullOrEmpty(categoryNameFilter) is false) { - query.Add("$filter", $"contains(Name,'{categoryNameFilter}')"); + categoryController.AddQueryString("$filter", $"contains(Name,'{categoryNameFilter}')"); } if (req.GetSortByProperties().Any()) { - query.Add("$orderby", string.Join(", ", req.GetSortByProperties().Select(p => $"{p.PropertyName} {(p.Direction == BitDataGridSortDirection.Ascending ? "asc" : "desc")}"))); + categoryController.AddQueryString("$orderby", string.Join(", ", req.GetSortByProperties().Select(p => $"{p.PropertyName} {(p.Direction == BitDataGridSortDirection.Ascending ? "asc" : "desc")}"))); } - var url = NavigationManager.GetUriWithQueryParameters("Category/GetCategories", query); - - var data = await HttpClient.GetFromJsonAsync(url, AppJsonContext.Default.PagedResultCategoryDto, CurrentCancellationToken) ?? new(); + var data = await categoryController.GetCategories(CurrentCancellationToken); return BitDataGridItemsProviderResult.From(await data.Items!.ToListAsync(CurrentCancellationToken)!, (int)data.TotalCount); } @@ -98,7 +100,7 @@ private async Task DeleteCategory(CategoryDto category) if (confirmed) { - await HttpClient.DeleteAsync($"Category/Delete/{category.Id}", CurrentCancellationToken); + await categoryController.Delete(category.Id, CurrentCancellationToken); await RefreshData(); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/DashboardPage.razor b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/DashboardPage.razor index a42a5dcd65..268d6a2351 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/DashboardPage.razor +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/DashboardPage.razor @@ -11,7 +11,7 @@ else
- +
diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/OverallStatsWidget.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/OverallStatsWidget.razor.cs index 16d24a9e2e..c52cc3fef1 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/OverallStatsWidget.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/OverallStatsWidget.razor.cs @@ -1,9 +1,12 @@ -using Boilerplate.Shared.Dtos.Dashboard; +using Boilerplate.Client.Core.Controllers.Dashboard; +using Boilerplate.Shared.Dtos.Dashboard; namespace Boilerplate.Client.Core.Components.Pages.Dashboard; public partial class OverallStatsWidget { + [AutoInject] IDashboardController dashboardController = default!; + private bool isLoading; private OverallAnalyticsStatsDataResponseDto data = new(); @@ -18,9 +21,7 @@ private async Task GetData() try { - data = await PrerenderStateService.GetValue($"{nameof(DashboardPage)}-{nameof(OverallStatsWidget)}", - async () => await HttpClient.GetFromJsonAsync($"Dashboard/GetOverallAnalyticsStatsData", - AppJsonContext.Default.OverallAnalyticsStatsDataResponseDto, CurrentCancellationToken)) ?? new(); + data = await dashboardController.GetOverallAnalyticsStatsData(CurrentCancellationToken); } finally { diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategotyWidget.razor b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategoryWidget.razor similarity index 100% rename from src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategotyWidget.razor rename to src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategoryWidget.razor diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategotyWidget.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategoryWidget.razor.cs similarity index 66% rename from src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategotyWidget.razor.cs rename to src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategoryWidget.razor.cs index 758d21d39f..7113f8832c 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategotyWidget.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategoryWidget.razor.cs @@ -1,7 +1,10 @@ -namespace Boilerplate.Client.Core.Components.Pages.Dashboard; +using Boilerplate.Client.Core.Controllers.Dashboard; -public partial class ProductsCountPerCategotyWidget +namespace Boilerplate.Client.Core.Components.Pages.Dashboard; + +public partial class ProductsCountPerCategoryWidget { + [AutoInject] IDashboardController dashboardController = default!; private bool isLoading; private BitChart? chart; @@ -30,9 +33,7 @@ private async Task GetData() { isLoading = true; - var data = await PrerenderStateService.GetValue($"{nameof(DashboardPage)}-{nameof(ProductsCountPerCategotyWidget)}", - async () => await HttpClient.GetFromJsonAsync($"Dashboard/GetProductsCountPerCategotyStats", - AppJsonContext.Default.ListProductsCountPerCategoryResponseDto, CurrentCancellationToken)) ?? []; + var data = await (await dashboardController.GetProductsCountPerCategoryStats(CurrentCancellationToken)).ToListAsync(CurrentCancellationToken); BitChartBarDataset chartDataSet = [.. data.Select(d => d.ProductCount)]; chartDataSet.BackgroundColor = data.Select(d => d.CategoryColor ?? string.Empty).ToArray(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategotyWidget.razor.scss b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategoryWidget.razor.scss similarity index 100% rename from src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategotyWidget.razor.scss rename to src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsCountPerCategoryWidget.razor.scss diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsPercentageWidget.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsPercentageWidget.razor.cs index 94442f2796..2555c2d79d 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsPercentageWidget.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsPercentageWidget.razor.cs @@ -1,7 +1,11 @@ -namespace Boilerplate.Client.Core.Components.Pages.Dashboard; +using Boilerplate.Client.Core.Controllers.Dashboard; + +namespace Boilerplate.Client.Core.Components.Pages.Dashboard; public partial class ProductsPercentageWidget { + [AutoInject] IDashboardController dashboardController = default!; + private bool isLoading; private BitChartPieConfig config = default!; @@ -24,9 +28,7 @@ private async Task GetData() try { - var data = await PrerenderStateService.GetValue($"{nameof(DashboardPage)}-{nameof(ProductsPercentageWidget)}", - async () => await HttpClient.GetFromJsonAsync($"Dashboard/GetProductsPercentagePerCategoryStats", - AppJsonContext.Default.ListProductPercentagePerCategoryResponseDto, CurrentCancellationToken)) ?? []; + var data = await dashboardController.GetProductsPercentagePerCategoryStats(CurrentCancellationToken); BitChartPieDataset chartDataSet = [.. data!.Select(d => d.ProductPercentage)]; chartDataSet.BackgroundColor = data.Select(d => d.CategoryColor ?? string.Empty).ToArray(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsSalesWidget.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsSalesWidget.razor.cs index c375d57b0f..fb60746693 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsSalesWidget.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Dashboard/ProductsSalesWidget.razor.cs @@ -1,7 +1,11 @@ -namespace Boilerplate.Client.Core.Components.Pages.Dashboard; +using Boilerplate.Client.Core.Controllers.Dashboard; + +namespace Boilerplate.Client.Core.Components.Pages.Dashboard; public partial class ProductsSalesWidget { + [AutoInject] IDashboardController dashboardController = default!; + private bool isLoading; private BitChart? chart; private BitChartBarConfig config = default!; @@ -29,9 +33,7 @@ private async Task GetData() { isLoading = true; - var data = await PrerenderStateService.GetValue($"{nameof(DashboardPage)}-{nameof(ProductsSalesWidget)}", - async () => await HttpClient.GetFromJsonAsync($"Dashboard/GetProductsSalesStats", - AppJsonContext.Default.ListProductSaleStatResponseDto, CurrentCancellationToken)) ?? []; + var data = await (await dashboardController.GetProductsSalesStats(CurrentCancellationToken)).ToListAsync(CurrentCancellationToken); BitChartBarDataset chartDataSet = [.. data.Select(d => d.SaleAmount)]; chartDataSet.BackgroundColor = data.Select(d => d.CategoryColor ?? string.Empty).ToArray(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/DeleteAccountConfirmModal.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/DeleteAccountConfirmModal.razor.cs index 0d10e401d5..51a43307b2 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/DeleteAccountConfirmModal.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/DeleteAccountConfirmModal.razor.cs @@ -1,7 +1,11 @@ -namespace Boilerplate.Client.Core.Components.Pages.Identity; +using Boilerplate.Client.Core.Controllers.Identity; + +namespace Boilerplate.Client.Core.Components.Pages.Identity; public partial class DeleteAccountConfirmModal { + [AutoInject] IUserController userController = default!; + [Parameter] public bool IsOpen { get; set; } [Parameter] public EventCallback IsOpenChanged { get; set; } @@ -15,7 +19,7 @@ private async Task CloseModal() private async Task DeleteAccount() { - await HttpClient.DeleteAsync("User/Delete", CurrentCancellationToken); + await userController.Delete(CurrentCancellationToken); await AuthenticationManager.SignOut(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/EditProfilePage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/EditProfilePage.razor.cs index 83672ecbc7..669d54a2a5 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/EditProfilePage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/EditProfilePage.razor.cs @@ -1,4 +1,5 @@ //-:cnd:noEmit +using Boilerplate.Client.Core.Controllers.Identity; using Boilerplate.Shared.Dtos.Identity; namespace Boilerplate.Client.Core.Components.Pages.Identity; @@ -6,6 +7,8 @@ namespace Boilerplate.Client.Core.Components.Pages.Identity; [Authorize] public partial class EditProfilePage { + [AutoInject] IUserController userController = default!; + private bool isSaving; private bool isRemoving; private bool isLoading; @@ -27,11 +30,11 @@ protected override async Task OnInitAsync() { await LoadEditProfileData(); - var access_token = await PrerenderStateService.GetValue($"{nameof(EditProfilePage)}-access_token", AuthTokenProvider.GetAccessTokenAsync); + var access_token = await PrerenderStateService.GetValue(AuthTokenProvider.GetAccessTokenAsync); - profileImageUploadUrl = $"{Configuration.GetApiServerAddress()}Attachment/UploadProfileImage?access_token={access_token}"; - profileImageUrl = $"{Configuration.GetApiServerAddress()}Attachment/GetProfileImage?access_token={access_token}"; - profileImageRemoveUrl = $"Attachment/RemoveProfileImage?access_token={access_token}"; + profileImageUploadUrl = $"{Configuration.GetApiServerAddress()}api/Attachment/UploadProfileImage?access_token={access_token}"; + profileImageUrl = $"{Configuration.GetApiServerAddress()}api/Attachment/GetProfileImage?access_token={access_token}"; + profileImageRemoveUrl = $"api/Attachment/RemoveProfileImage?access_token={access_token}"; } finally { @@ -45,7 +48,7 @@ private async Task LoadEditProfileData() { user = await GetCurrentUser() ?? new(); - UpdateEditProfileData(); + user.Patch(userToEdit); } private async Task RefreshProfileData() @@ -55,14 +58,7 @@ private async Task RefreshProfileData() PubSubService.Publish(PubSubMessages.PROFILE_UPDATED, user); } - private void UpdateEditProfileData() - { - userToEdit.Gender = user.Gender; - userToEdit.FullName = user.FullName; - userToEdit.BirthDate = user.BirthDate; - } - - private Task GetCurrentUser() => PrerenderStateService.GetValue($"{nameof(EditProfilePage)}-{nameof(user)}", () => HttpClient.GetFromJsonAsync("User/GetCurrentUser", AppJsonContext.Default.UserDto)); + private Task GetCurrentUser() => userController.GetCurrentUser(CurrentCancellationToken); private async Task DoSave() { @@ -73,12 +69,9 @@ private async Task DoSave() try { - user.FullName = userToEdit.FullName; - user.BirthDate = userToEdit.BirthDate; - user.Gender = userToEdit.Gender; + userToEdit.Patch(user); - (await (await HttpClient.PutAsJsonAsync("User/Update", userToEdit, AppJsonContext.Default.EditUserDto, CurrentCancellationToken)) - .Content.ReadFromJsonAsync(AppJsonContext.Default.UserDto, CurrentCancellationToken))!.Patch(user); + (await userController.Update(userToEdit, CurrentCancellationToken)).Patch(user); PubSubService.Publish(PubSubMessages.PROFILE_UPDATED, user); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/EmailConfirmationPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/EmailConfirmationPage.razor.cs index 0b30116c94..e6e80a04f7 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/EmailConfirmationPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/EmailConfirmationPage.razor.cs @@ -1,7 +1,11 @@ -namespace Boilerplate.Client.Core.Components.Pages.Identity; +using Boilerplate.Client.Core.Controllers.Identity; + +namespace Boilerplate.Client.Core.Components.Pages.Identity; public partial class EmailConfirmationPage { + [AutoInject] IIdentityController identityController = default!; + private bool isLoading; private string? resendLinkErrors; private BitMessageBarType emailConfirmationMessageType = BitMessageBarType.Error; @@ -29,7 +33,7 @@ private async Task DoResendLink() try { - await HttpClient.PostAsJsonAsync("Identity/SendConfirmationEmail", new() { Email = Email }, AppJsonContext.Default.SendConfirmationEmailRequestDto, CurrentCancellationToken); + await identityController.SendConfirmationEmail(new() { Email = Email }, CurrentCancellationToken); emailConfirmationMessageType = BitMessageBarType.Success; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/ForgotPasswordPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/ForgotPasswordPage.razor.cs index 6dcd103166..43604610a7 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/ForgotPasswordPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/ForgotPasswordPage.razor.cs @@ -1,9 +1,12 @@ -using Boilerplate.Shared.Dtos.Identity; +using Boilerplate.Client.Core.Controllers.Identity; +using Boilerplate.Shared.Dtos.Identity; namespace Boilerplate.Client.Core.Components.Pages.Identity; public partial class ForgotPasswordPage { + [AutoInject] IIdentityController identityController = default!; + private bool isLoading; private string? forgotPasswordMessage; private BitMessageBarType forgotPasswordMessageType; @@ -18,7 +21,7 @@ private async Task DoSubmit() try { - await HttpClient.PostAsJsonAsync("Identity/SendResetPasswordEmail", forgotPasswordModel, AppJsonContext.Default.SendResetPasswordEmailRequestDto, CurrentCancellationToken); + await identityController.SendResetPasswordEmail(forgotPasswordModel, CurrentCancellationToken); forgotPasswordMessageType = BitMessageBarType.Success; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/ResetPasswordPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/ResetPasswordPage.razor.cs index 0e109eb92c..d2993d4a35 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/ResetPasswordPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/ResetPasswordPage.razor.cs @@ -1,9 +1,12 @@ -using Boilerplate.Shared.Dtos.Identity; +using Boilerplate.Client.Core.Controllers.Identity; +using Boilerplate.Shared.Dtos.Identity; namespace Boilerplate.Client.Core.Components.Pages.Identity; public partial class ResetPasswordPage { + [AutoInject] IIdentityController identityController = default!; + private bool isLoading; private string? resetPasswordMessage; private BitMessageBarType resetPasswordMessageType; @@ -40,7 +43,7 @@ private async Task DoSubmit() try { - await HttpClient.PostAsJsonAsync("Identity/ResetPassword", resetPasswordModel, AppJsonContext.Default.ResetPasswordRequestDto, CurrentCancellationToken); + await identityController.ResetPassword(resetPasswordModel, CurrentCancellationToken); resetPasswordMessageType = BitMessageBarType.Success; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignUpPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignUpPage.razor.cs index 018bdcb862..c57c5b12e3 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignUpPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Identity/SignUpPage.razor.cs @@ -1,16 +1,18 @@ -using Boilerplate.Shared.Dtos.Identity; +using Boilerplate.Client.Core.Controllers.Identity; +using Boilerplate.Shared.Dtos.Identity; namespace Boilerplate.Client.Core.Components.Pages.Identity; public partial class SignUpPage { + [AutoInject] IIdentityController identityController = default!; + private bool isLoading; private bool isSignedUp; private string? signUpMessage; private BitMessageBarType signUpMessageType; private SignUpRequestDto signUpModel = new(); - protected override async Task OnAfterFirstRenderAsync() { await base.OnAfterFirstRenderAsync(); @@ -30,7 +32,7 @@ private async Task DoSignUp() try { - await HttpClient.PostAsJsonAsync("Identity/SignUp", signUpModel, AppJsonContext.Default.SignUpRequestDto, CurrentCancellationToken); + await identityController.SignUp(signUpModel, CurrentCancellationToken); isSignedUp = true; } @@ -59,7 +61,7 @@ private async Task DoResendLink() try { - await HttpClient.PostAsJsonAsync("Identity/SendConfirmationEmail", new() { Email = signUpModel.Email }, AppJsonContext.Default.SendConfirmationEmailRequestDto, CurrentCancellationToken); + await identityController.SendConfirmationEmail(new() { Email = signUpModel.Email }, CurrentCancellationToken); signUpMessageType = BitMessageBarType.Success; signUpMessage = Localizer[nameof(AppStrings.ResendConfirmationLinkMessage)]; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/NotAuthorizedPage.razor b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/NotAuthorizedPage.razor index 3ef68a54eb..415cc719e3 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/NotAuthorizedPage.razor +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/NotAuthorizedPage.razor @@ -4,7 +4,7 @@
-
+

@Localizer[nameof(AppStrings.ForbiddenException)]

@Localizer[nameof(AppStrings.YouAreSignInAs)] @user.GetUserName()

diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/NotAuthorizedPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/NotAuthorizedPage.razor.cs index 03ced70bae..993a310cee 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/NotAuthorizedPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/NotAuthorizedPage.razor.cs @@ -21,7 +21,7 @@ protected override async Task OnAfterFirstRenderAsync() // Following this procedure, the newly acquired access token may now include the necessary roles or claims. // To prevent infinitie redirect loop, let's append refresh_token=false to the url, so we only redirect in case no refresh_token=false is present - if (string.IsNullOrEmpty(refresh_token) is false && RedirectUrl?.Contains("refresh_token=false", StringComparison.InvariantCulture) is null or false) + if (string.IsNullOrEmpty(refresh_token) is false && RedirectUrl?.Contains("try_refreshing_token=false", StringComparison.InvariantCulture) is null or false) { await AuthenticationManager.RefreshToken(); @@ -30,7 +30,7 @@ protected override async Task OnAfterFirstRenderAsync() if (RedirectUrl is not null) { var @char = RedirectUrl.Contains('?') ? '&' : '?'; // The RedirectUrl may already include a query string. - NavigationManager.NavigateTo($"{RedirectUrl}{@char}refresh_token=false"); + NavigationManager.NavigateTo($"{RedirectUrl}{@char}try_refreshing_token=false"); } } } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Products/AddOrEditProductModal.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Products/AddOrEditProductModal.razor.cs index 27a63493e8..1b978b306f 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Products/AddOrEditProductModal.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Products/AddOrEditProductModal.razor.cs @@ -1,9 +1,13 @@ -using Boilerplate.Shared.Dtos.Products; +using Boilerplate.Client.Core.Controllers.Categories; +using Boilerplate.Client.Core.Controllers.Product; +using Boilerplate.Shared.Dtos.Products; namespace Boilerplate.Client.Core.Components.Pages.Products; public partial class AddOrEditProductModal { + [AutoInject] ICategoryController categoryController = default!; + [AutoInject] IProductController productController = default!; private bool isOpen; private bool isLoading; @@ -39,9 +43,7 @@ private async Task LoadAllCategoriesAsync() try { - var categoryList = await PrerenderStateService.GetValue($"{nameof(ProductsPage)}-AllCategoryList", - async () => await HttpClient.GetFromJsonAsync("Category/Get", - AppJsonContext.Default.ListCategoryDto, CurrentCancellationToken)) ?? []; + var categoryList = await (await categoryController.Get(CurrentCancellationToken)).ToListAsync(CurrentCancellationToken); allCategoryList = categoryList.Select(c => new BitDropdownItem() { @@ -66,11 +68,11 @@ private async Task Save() { if (product.Id == 0) { - await HttpClient.PostAsJsonAsync("Product/Create", product, AppJsonContext.Default.ProductDto, CurrentCancellationToken); + await productController.Create(product, CurrentCancellationToken); } else { - await HttpClient.PutAsJsonAsync("Product/Update", product, AppJsonContext.Default.ProductDto, CurrentCancellationToken); + await productController.Update(product, CurrentCancellationToken); } isOpen = false; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Products/ProductsPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Products/ProductsPage.razor.cs index 2488469cfb..10ae347b16 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Products/ProductsPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Products/ProductsPage.razor.cs @@ -1,4 +1,5 @@ //-:cnd:noEmit +using Boilerplate.Client.Core.Controllers.Product; using Boilerplate.Shared.Dtos.Products; namespace Boilerplate.Client.Core.Components.Pages.Products; @@ -6,6 +7,8 @@ namespace Boilerplate.Client.Core.Components.Pages.Products; [Authorize] public partial class ProductsPage { + [AutoInject] IProductController productController = default!; + private bool isLoading; private AddOrEditProductModal? modal; private string productNameFilter = string.Empty; @@ -41,25 +44,23 @@ private void PrepareGridDataProvider() try { // https://docs.microsoft.com/en-us/odata/concepts/queryoptions-overview - var query = new Dictionary() + productController.AddQueryStrings(new () { { "$top", req.Count ?? 10 }, { "$skip", req.StartIndex } - }; + }); if (string.IsNullOrEmpty(productNameFilter) is false) { - query.Add("$filter", $"contains(Name,'{productNameFilter}')"); + productController.AddQueryString("$filter", $"contains(Name,'{productNameFilter}')"); } if (req.GetSortByProperties().Any()) { - query.Add("$orderby", string.Join(", ", req.GetSortByProperties().Select(p => $"{p.PropertyName} {(p.Direction == BitDataGridSortDirection.Ascending ? "asc" : "desc")}"))); + productController.AddQueryString("$orderby", string.Join(", ", req.GetSortByProperties().Select(p => $"{p.PropertyName} {(p.Direction == BitDataGridSortDirection.Ascending ? "asc" : "desc")}"))); } - var url = NavigationManager.GetUriWithQueryParameters("Product/GetProducts", query); - - var data = await HttpClient.GetFromJsonAsync(url, AppJsonContext.Default.PagedResultProductDto, CurrentCancellationToken); + var data = await productController.GetProducts(CurrentCancellationToken); return BitDataGridItemsProviderResult.From(await data!.Items!.ToListAsync(), (int)data!.TotalCount); } @@ -99,7 +100,7 @@ private async Task DeleteProduct(ProductDto product) if (confirmed) { - await HttpClient.DeleteAsync($"Product/Delete/{product.Id}", CurrentCancellationToken); + await productController.Delete(product.Id, CurrentCancellationToken); await RefreshData(); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Todo/TodoPage.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Todo/TodoPage.razor.cs index 1b3ecf4140..5993e29923 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Todo/TodoPage.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Todo/TodoPage.razor.cs @@ -1,10 +1,13 @@ -using Boilerplate.Shared.Dtos.Todo; +using Boilerplate.Client.Core.Controllers.Todo; +using Boilerplate.Shared.Dtos.Todo; namespace Boilerplate.Client.Core.Components.Pages.Todo; [Authorize] public partial class TodoPage { + [AutoInject] ITodoItemController todoItemController = default!; + private bool isAdding; private bool isLoading; private string? searchText; @@ -39,8 +42,7 @@ private async Task LoadTodoItems() try { - allTodoItems = await PrerenderStateService.GetValue($"{nameof(TodoPage)}-allTodoItems", - async () => await HttpClient.GetFromJsonAsync("TodoItem/Get", AppJsonContext.Default.ListTodoItemDto, CurrentCancellationToken)) ?? []; + allTodoItems = await (await todoItemController.Get(CurrentCancellationToken)).ToListAsync(CurrentCancellationToken); FilterViewTodoItems(); } @@ -112,8 +114,7 @@ private async Task AddTodoItem() try { - var addedTodoItem = await (await HttpClient.PostAsJsonAsync("TodoItem/Create", new() { Title = newTodoTitle }, AppJsonContext.Default.TodoItemDto, CurrentCancellationToken)) - .Content.ReadFromJsonAsync(AppJsonContext.Default.TodoItemDto, CurrentCancellationToken); + var addedTodoItem = await todoItemController.Create(new() { Title = newTodoTitle }, CurrentCancellationToken); allTodoItems.Add(addedTodoItem!); @@ -145,7 +146,7 @@ private async Task DeleteTodoItem(TodoItemDto todoItem) StateHasChanged(); - await HttpClient.DeleteAsync($"TodoItem/Delete/{todoItem.Id}", CurrentCancellationToken); + await todoItemController.Delete(todoItem.Id, CurrentCancellationToken); allTodoItems.Remove(todoItem); @@ -178,8 +179,7 @@ private async Task SaveTodoItem(TodoItemDto todoItem) private async Task UpdateTodoItem(TodoItemDto todoItem) { - (await (await HttpClient.PutAsJsonAsync("TodoItem/Update", todoItem, AppJsonContext.Default.TodoItemDto, CurrentCancellationToken)) - .Content.ReadFromJsonAsync(AppJsonContext.Default.TodoItemDto, CurrentCancellationToken))!.Patch(todoItem); + (await todoItemController.Update(todoItem, CurrentCancellationToken)).Patch(todoItem); todoItem.IsInEditMode = false; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Attributes.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Attributes.cs new file mode 100644 index 0000000000..a1c6c2e55b --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Attributes.cs @@ -0,0 +1,37 @@ +namespace Boilerplate.Client.Core.Controllers; + +[AttributeUsage(AttributeTargets.Interface)] +internal class RouteAttribute(string template) : Attribute +{ + public string Template { get; } = template; +} + +[AttributeUsage(AttributeTargets.Method)] +internal class HttpGetAttribute(string? template = null) : Attribute +{ + public string? Template { get; } = template; +} + +[AttributeUsage(AttributeTargets.Method)] +internal class HttpPostAttribute(string? template = null) : Attribute +{ + public string? Template { get; } = template; +} + +[AttributeUsage(AttributeTargets.Method)] +internal class HttpPutAttribute(string? template = null) : Attribute +{ + public string? Template { get; } = template; +} + +[AttributeUsage(AttributeTargets.Method)] +internal class HttpDeleteAttribute(string? template = null) : Attribute +{ + public string? Template { get; } = template; +} + +[AttributeUsage(AttributeTargets.Method)] +internal class HttpPatchAttribute(string? template = null) : Attribute +{ + public string? Template { get; } = template; +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Categories/ICategoryController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Categories/ICategoryController.cs new file mode 100644 index 0000000000..019b6b91d9 --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Categories/ICategoryController.cs @@ -0,0 +1,25 @@ +using Boilerplate.Shared.Dtos.Categories; + +namespace Boilerplate.Client.Core.Controllers.Categories; + +[Route("api/[controller]/[action]/")] +public interface ICategoryController : IAppController +{ + [HttpGet("{id}")] + Task Get(int id, CancellationToken cancellationToken = default); + + [HttpPost] + Task Create(CategoryDto body, CancellationToken cancellationToken = default); + + [HttpPut] + Task Update(CategoryDto body, CancellationToken cancellationToken = default); + + [HttpDelete("{id}")] + Task Delete(int id, CancellationToken cancellationToken = default); + + [HttpGet] + Task> GetCategories(CancellationToken cancellationToken = default) => default!; + + [HttpGet] + Task> Get(CancellationToken cancellationToken) => default!; +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Dashboard/IDashboardController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Dashboard/IDashboardController.cs new file mode 100644 index 0000000000..57811ede22 --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Dashboard/IDashboardController.cs @@ -0,0 +1,19 @@ +using Boilerplate.Shared.Dtos.Dashboard; + +namespace Boilerplate.Client.Core.Controllers.Dashboard; + +[Route("api/[controller]/[action]/")] +public interface IDashboardController : IAppController +{ + [HttpGet] + Task GetOverallAnalyticsStatsData(CancellationToken cancellationToken = default); + + [HttpGet] + Task> GetProductsCountPerCategoryStats(CancellationToken cancellationToken = default); + + [HttpGet] + Task> GetProductsSalesStats(CancellationToken cancellationToken = default); + + [HttpGet] + Task GetProductsPercentagePerCategoryStats(CancellationToken cancellationToken = default); +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/IAppController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/IAppController.cs new file mode 100644 index 0000000000..1c0a266047 --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/IAppController.cs @@ -0,0 +1,7 @@ +namespace Boilerplate.Client.Core.Controllers; + +public interface IAppController +{ + void AddQueryString(string key, object? value) { } + void AddQueryStrings(Dictionary queryString) { } +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/IMinimalApiController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/IMinimalApiController.cs new file mode 100644 index 0000000000..90bef60871 --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/IMinimalApiController.cs @@ -0,0 +1,9 @@ +using System.Text.Json; + +namespace Boilerplate.Client.Core.Controllers; + +public interface IMinimalApiController : IAppController +{ + [HttpGet("api/minimal-api-sample/{routeParameter}{?queryStringParameter}")] + Task MinimalApiSample(string routeParameter, string queryStringParameter, CancellationToken cancellationToken = default); +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Identity/IIdentityController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Identity/IIdentityController.cs new file mode 100644 index 0000000000..a429ac2718 --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Identity/IIdentityController.cs @@ -0,0 +1,25 @@ +using Boilerplate.Shared.Dtos.Identity; + +namespace Boilerplate.Client.Core.Controllers.Identity; + +[Route("api/[controller]/[action]/")] +public interface IIdentityController : IAppController +{ + [HttpPost] + Task SignUp(SignUpRequestDto body, CancellationToken cancellationToken = default); + + [HttpPost] + Task SendConfirmationEmail(SendConfirmationEmailRequestDto body, CancellationToken cancellationToken = default); + + [HttpPost] + Task SendResetPasswordEmail(SendResetPasswordEmailRequestDto body, CancellationToken cancellationToken = default); + + [HttpPost] + Task ResetPassword(ResetPasswordRequestDto body, CancellationToken cancellationToken = default); + + [HttpPost] + Task Refresh(RefreshRequestDto body, CancellationToken cancellationToken = default) => default!; + + [HttpPost] + Task SignIn(SignInRequestDto body, CancellationToken cancellationToken = default) => default!; +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Identity/IUserController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Identity/IUserController.cs new file mode 100644 index 0000000000..38caf66acd --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Identity/IUserController.cs @@ -0,0 +1,16 @@ +using Boilerplate.Shared.Dtos.Identity; + +namespace Boilerplate.Client.Core.Controllers.Identity; + +[Route("api/[controller]/[action]/")] +public interface IUserController : IAppController +{ + [HttpGet] + Task GetCurrentUser(CancellationToken cancellationToken = default); + + [HttpPut] + Task Update(EditUserDto body, CancellationToken cancellationToken = default); + + [HttpDelete] + Task Delete(CancellationToken cancellationToken = default); +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Products/IProductController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Products/IProductController.cs new file mode 100644 index 0000000000..fa1f03d6e9 --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Products/IProductController.cs @@ -0,0 +1,22 @@ +using Boilerplate.Shared.Dtos.Products; + +namespace Boilerplate.Client.Core.Controllers.Product; + +[Route("api/[controller]/[action]/")] +public interface IProductController : IAppController +{ + [HttpGet("{id}")] + Task Get(int id, CancellationToken cancellationToken = default); + + [HttpPost] + Task Create(ProductDto body, CancellationToken cancellationToken = default); + + [HttpPut] + Task Update(ProductDto body, CancellationToken cancellationToken = default); + + [HttpDelete("{id}")] + Task Delete(int id, CancellationToken cancellationToken = default); + + [HttpGet] + Task> GetProducts(CancellationToken cancellationToken = default) => default!; +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Readme.md b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Readme.md new file mode 100644 index 0000000000..801e2faf1b --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Readme.md @@ -0,0 +1,56 @@ +**Bit.SourceGenerator interface based HttpClient proxy generator** + +**Introduction:** +When defining server-side APIs, there are no restrictions. You can leverage features such as Api versioning, OData, ASP.NET Core Minimal API, +Middleware, and more. On the client side, use HttpClient and optionally employ Bit.SourceGenerator. + +Getting started: + +1- Creating a Custom Interface: +Define an interface, for instance, `ICategoryController`, extending `IAppController`. + +```csharp +public interface ICategoryController : IAppController +``` + +2- Simply inject these interfaces into your classes, and you're all set! + +3- (Optional) implement that interface in server project. +```csharp +public class CategoryController : AppControllerBase, ICategoryController +``` +Interface implementation on the server-side is not mandatory nor possible in some situations (For example ASP.NET Core Minimal API) + +**Note:** If you implement the interface on the server-side, C# compiler ensure +that methods seen by the client in `ICategoryController` are present in `CategoryController` during build. + +**Note:** Server-side methods may have conditions that make direct definition in the client-side interface challenging. +For example, an `Upload` method in `AttachmentController` has `IFormFile`, +and `Refresh` method of `IdentityController` returns `ActionResult` and these types are not present in client side. +In this case you can still use `Bit.SourceGenerator`, but in order to prevent C# compiler's build error, write the followings: +```csharp +[HttpPost] +Task Refresh(RefreshRequestDto body) => default!; +``` +instead of +```csharp +[HttpPost] +Task Refresh(RefreshRequestDto body); +``` + +**Convention Over Configuration:** + +While following the Convention over Configuration principle, methods like `Create` in `ICategoryController` send requests to `api/Category/Create`, +you are not bound by this convention. Use any `RoutePrefix` you prefer, as long as your API is accepting/returning json you're all set! + +**Advanced sample**: +Explore `IMinimalApiController` for example of ASP.NET Core Minimal API that has the following characteristics: + +1- No server-side web api controllers because of ASP.NET Core Minimal API. + +2- Receiving output as `JsonDocument`. + +3- Example of Query String. + +**Note:** We supprt [RFC6570](https://datatracker.ietf.org/doc/html/rfc6570) for request url templates thanks to [DoLess.UriTemplates](https://github.com/letsar/DoLess.UriTemplates?tab=readme-ov-file#examples)! + diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Todo/ITodoItemController.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Todo/ITodoItemController.cs new file mode 100644 index 0000000000..7761b56e28 --- /dev/null +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Controllers/Todo/ITodoItemController.cs @@ -0,0 +1,22 @@ +using Boilerplate.Shared.Dtos.Todo; + +namespace Boilerplate.Client.Core.Controllers.Todo; + +[Route("api/[controller]/[action]/")] +public interface ITodoItemController : IAppController +{ + [HttpGet("{id}")] + Task Get(int id, CancellationToken cancellationToken = default); + + [HttpPost] + Task Create(TodoItemDto body, CancellationToken cancellationToken = default); + + [HttpPut] + Task Update(TodoItemDto body, CancellationToken cancellationToken = default); + + [HttpDelete("{id}")] + Task Delete(int id, CancellationToken cancellationToken = default); + + [HttpGet] + Task> Get(CancellationToken cancellationToken = default) => default!; +} diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IServiceCollectionExtensions.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IServiceCollectionExtensions.cs index 0d785b575d..901069e04d 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IServiceCollectionExtensions.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IServiceCollectionExtensions.cs @@ -17,7 +17,7 @@ public static IServiceCollection AddClientSharedServices(this IServiceCollection services.TryAddTransient(); services.TryAddTransient(); - services.TryAddTransient(); + services.TryAddKeyedTransient("DefaultMessageHandler"); services.TryAddTransient(); services.TryAddTransient(); services.TryAddTransient(); @@ -29,6 +29,9 @@ public static IServiceCollection AddClientSharedServices(this IServiceCollection services.TryAddTransient(); services.TryAddTransient(); + services.TryAddTransient(sp => AppJsonContext.Default.Options); + services.AddTypedHttpClients(); + services.AddBitBlazorUIServices(); services.AddSharedServices(); @@ -43,7 +46,7 @@ public static IServiceCollection AddSessioned(this IS where TImplementation : class, TService where TService : class { - if (AppRenderMode.IsHybrid() || OperatingSystem.IsBrowser()) + if (AppRenderMode.IsBlazorHybrid || OperatingSystem.IsBrowser()) { return services.AddSingleton(); } @@ -60,7 +63,7 @@ public static IServiceCollection TryAddSessioned(this where TImplementation : class, TService where TService : class { - if (AppRenderMode.IsHybrid() || OperatingSystem.IsBrowser()) + if (AppRenderMode.IsBlazorHybrid || OperatingSystem.IsBrowser()) { services.TryAddSingleton(); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Routes.razor.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Routes.razor.cs index b2b88ef5fa..41b3f32565 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Routes.razor.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Routes.razor.cs @@ -2,5 +2,58 @@ public partial class Routes { + [AutoInject] IJSRuntime jsRuntime = default!; + [AutoInject] IBitDeviceCoordinator bitDeviceCoordinator = default!; + [AutoInject] IStorageService storageService = default!; + protected override async Task OnInitializedAsync() + { + if (AppRenderMode.IsBlazorHybrid) + { + if (AppRenderMode.MultilingualEnabled) + { + CultureInfoManager.SetCurrentCulture(await storageService.GetItem("Culture")); + } + + await SetupBodyClasses(); + } + + await base.OnInitializedAsync(); + } + + private async Task SetupBodyClasses() + { + var cssClasses = new List { }; + + if (OperatingSystem.IsWindows()) + { + cssClasses.Add("bit-windows"); + } + else if (OperatingSystem.IsMacOS() || OperatingSystem.IsMacCatalyst()) + { + cssClasses.Add("bit-macos"); + } + else if (OperatingSystem.IsIOS() && OperatingSystem.IsMacCatalyst() is false) + { + cssClasses.Add("bit-ios"); + } + else if (OperatingSystem.IsAndroid()) + { + cssClasses.Add("bit-android"); + } + + var cssVariables = new Dictionary(); + var statusBarHeight = bitDeviceCoordinator.GetStatusBarHeight(); + + if (OperatingSystem.IsMacCatalyst() is false) + { + //For iOS this is handled in css using safe-area env() variables + //For Android there's an issue with keyboard in fullscreen mode. more info: https://github.com/bitfoundation/bitplatform/issues/5626 + //For Windows there's an issue with TitleBar. more info: https://github.com/bitfoundation/bitplatform/issues/5695 + statusBarHeight = 0; + } + + cssVariables.Add("--bit-status-bar-height", $"{statusBarHeight.ToString("F3", CultureInfo.InvariantCulture)}px"); + await jsRuntime.ApplyBodyElementClasses(cssClasses, cssVariables); + } } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AppRenderMode.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AppRenderMode.cs index 0461cd710b..affc20667c 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AppRenderMode.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AppRenderMode.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Components.Web; -using OS = System.OperatingSystem; namespace Boilerplate.Client.Core.Services; @@ -22,5 +21,15 @@ public static class AppRenderMode false; #endif - public static bool IsHybrid() => OS.IsAndroid() || OS.IsIOS() || OS.IsMacCatalyst() || OS.IsMacOS() || OS.IsWindows(); + public static bool MultilingualEnabled { get; } = +#if MultilingualEnabled + true; +#else + false; +#endif + + /// + /// Is running under .NET MAUI? + /// + public static bool IsBlazorHybrid { get; set; } } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthenticationManager.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthenticationManager.cs index 1c8acef044..e8e83b7b07 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthenticationManager.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthenticationManager.cs @@ -1,6 +1,7 @@ using System.Text; using System.Text.Json; using Boilerplate.Shared.Dtos.Identity; +using Boilerplate.Client.Core.Controllers.Identity; namespace Boilerplate.Client.Core.Services; @@ -9,13 +10,13 @@ public partial class AuthenticationManager : AuthenticationStateProvider [AutoInject] private IAuthTokenProvider tokenProvider = default!; [AutoInject] private IStorageService storageService = default!; [AutoInject] private IJSRuntime jsRuntime = default!; - [AutoInject] private HttpClient httpClient = default; + [AutoInject] private IIdentityController identityController = default; [AutoInject] private IStringLocalizer localizer = default!; + [AutoInject] private JsonSerializerOptions jsonSerializerOptions = default!; public async Task SignIn(SignInRequestDto signInModel, CancellationToken cancellationToken) { - var result = await (await httpClient.PostAsJsonAsync("Identity/SignIn", signInModel, AppJsonContext.Default.SignInRequestDto, cancellationToken)) - .Content.ReadFromJsonAsync(AppJsonContext.Default.TokenResponseDto, cancellationToken); + var result = await identityController.SignIn(signInModel, cancellationToken); await StoreToken(result!, signInModel.RememberMe); @@ -26,7 +27,7 @@ public async Task SignOut() { await storageService.RemoveItem("access_token"); await storageService.RemoveItem("refresh_token"); - if (AppRenderMode.PrerenderEnabled && AppRenderMode.IsHybrid() is false) + if (AppRenderMode.PrerenderEnabled && AppRenderMode.IsBlazorHybrid is false) { await jsRuntime.RemoveCookie("access_token"); } @@ -35,7 +36,7 @@ public async Task SignOut() public async Task RefreshToken() { - if (AppRenderMode.PrerenderEnabled && AppRenderMode.IsHybrid() is false) + if (AppRenderMode.PrerenderEnabled && AppRenderMode.IsBlazorHybrid is false) { await jsRuntime.RemoveCookie("access_token"); } @@ -59,9 +60,7 @@ public override async Task GetAuthenticationStateAsync() try { - var refreshTokenResponse = await (await httpClient.PostAsJsonAsync("Identity/Refresh", new() { RefreshToken = refresh_token }, AppJsonContext.Default.RefreshRequestDto)) - .Content.ReadFromJsonAsync(AppJsonContext.Default.TokenResponseDto); - + var refreshTokenResponse = await identityController.Refresh(new() { RefreshToken = refresh_token }); await StoreToken(refreshTokenResponse!); access_token = refreshTokenResponse!.AccessToken; } @@ -91,7 +90,7 @@ private async Task StoreToken(TokenResponseDto tokenResponseDto, bool? rememberM } await storageService.SetItem("access_token", tokenResponseDto!.AccessToken, rememberMe is true); await storageService.SetItem("refresh_token", tokenResponseDto!.RefreshToken, rememberMe is true); - if (AppRenderMode.PrerenderEnabled && AppRenderMode.IsHybrid() is false) + if (AppRenderMode.PrerenderEnabled && AppRenderMode.IsBlazorHybrid is false) { await jsRuntime.SetCookie("access_token", tokenResponseDto.AccessToken!, tokenResponseDto.ExpiresIn, rememberMe is true); } @@ -102,14 +101,14 @@ private static AuthenticationState NotSignedIn() return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); } - private static IEnumerable ParseTokenClaims(string access_token) + private IEnumerable ParseTokenClaims(string access_token) { return ParseJwt(access_token) .Select(keyValue => new Claim(keyValue.Key, keyValue.Value.ToString() ?? string.Empty)) .ToArray(); } - private static Dictionary ParseJwt(string access_token) + private Dictionary ParseJwt(string access_token) { // Split the token to get the payload string base64UrlPayload = access_token.Split('.')[1]; @@ -121,7 +120,7 @@ private static Dictionary ParseJwt(string access_token) string jsonPayload = Encoding.UTF8.GetString(Convert.FromBase64String(base64Payload)); // Deserialize the JSON string to a dictionary - var claims = JsonSerializer.Deserialize(jsonPayload, AppJsonContext.Default.DictionaryStringObject)!; + var claims = JsonSerializer.Deserialize(jsonPayload, jsonSerializerOptions.GetTypeInfo>())!; return claims; } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IPrerenderStateService.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IPrerenderStateService.cs index 4ef4bca93d..d0f897c997 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IPrerenderStateService.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/Contracts/IPrerenderStateService.cs @@ -1,4 +1,6 @@ -namespace Boilerplate.Client.Core.Services.Contracts; +using System.Runtime.CompilerServices; + +namespace Boilerplate.Client.Core.Services.Contracts; /// /// This service simplifies the process of persisting application state in Pre-Rendering mode @@ -13,5 +15,10 @@ public interface IPrerenderStateService /// one can easily use the following method () in the OnInit lifecycle method of the Blazor components or pages /// to retrieve everything that requires an async-await (like current user's info). /// + Task GetValue(Func> factory, + [CallerLineNumber] int lineNumber = 0, + [CallerMemberName] string memberName = "", + [CallerFilePath] string filePath = ""); + Task GetValue(string key, Func> factory); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs index f37f0b8c01..c4980643e0 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs @@ -1,8 +1,9 @@ using System.Net; +using System.Text.Json; namespace Boilerplate.Client.Core.Services.HttpMessageHandlers; -public class ExceptionDelegatingHandler(IStringLocalizer localizer, HttpClientHandler httpClientHandler) +public class ExceptionDelegatingHandler(IStringLocalizer localizer, JsonSerializerOptions jsonSerializerOptions, HttpClientHandler httpClientHandler) : DelegatingHandler(httpClientHandler) { protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) @@ -19,7 +20,7 @@ protected override async Task SendAsync(HttpRequestMessage { if (response.Headers.TryGetValues("Request-ID", out IEnumerable? values) && values is not null && values.Any()) { - RestErrorInfo restError = (await response!.Content.ReadFromJsonAsync(AppJsonContext.Default.RestErrorInfo, cancellationToken))!; + RestErrorInfo restError = (await response!.Content.ReadFromJsonAsync(jsonSerializerOptions.GetTypeInfo(), cancellationToken))!; Type exceptionType = typeof(RestErrorInfo).Assembly.GetType(restError.ExceptionType!) ?? typeof(UnknownException); @@ -50,7 +51,8 @@ protected override async Task SendAsync(HttpRequestMessage return response; } catch (Exception exp) when ((exp is HttpRequestException && serverCommunicationSuccess is false) - || exp is TaskCanceledException tcExp && tcExp.InnerException is TimeoutException) + || exp is TaskCanceledException tcExp && tcExp.InnerException is TimeoutException + || exp is HttpRequestException { StatusCode: HttpStatusCode.BadGateway or HttpStatusCode.GatewayTimeout or HttpStatusCode.ServiceUnavailable }) { throw new ServerConnectionException(nameof(AppStrings.ServerConnectionException), exp); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/HttpMessageHandlers/RequestHeadersDelegationHandler.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/HttpMessageHandlers/RequestHeadersDelegationHandler.cs index 451cc0a5f5..914fe92215 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/HttpMessageHandlers/RequestHeadersDelegationHandler.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/HttpMessageHandlers/RequestHeadersDelegationHandler.cs @@ -11,9 +11,10 @@ protected override async Task SendAsync(HttpRequestMessage request.SetBrowserRequestCredentials(BrowserRequestCredentials.Omit); request.SetBrowserResponseStreamingEnabled(true); -#if MultilingualEnabled - request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(CultureInfo.CurrentCulture.Name)); -#endif + if (AppRenderMode.MultilingualEnabled) + { + request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(CultureInfo.CurrentCulture.Name)); + } return await base.SendAsync(request, cancellationToken); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/PrerenderStateService.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/PrerenderStateService.cs index 30afb679fa..2746f63f38 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/PrerenderStateService.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/PrerenderStateService.cs @@ -1,5 +1,7 @@ //-:cnd:noEmit +using System.Runtime.CompilerServices; + namespace Boilerplate.Client.Core.Services; /// @@ -17,6 +19,19 @@ public PrerenderStateService(PersistentComponentState? persistentComponentState this.persistentComponentState = persistentComponentState; } + public async Task GetValue(Func> factory, + [CallerLineNumber] int lineNumber = 0, + [CallerMemberName] string memberName = "", + [CallerFilePath] string filePath = "") + { + if (AppRenderMode.PrerenderEnabled is false) + return await factory(); + + string key = $"{filePath.Split('\\').LastOrDefault()} {memberName} {lineNumber}"; + + return await GetValue(key, factory); + } + public async Task GetValue(string key, Func> factory) { if (AppRenderMode.PrerenderEnabled is false) diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/PubSubMessages.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/PubSubMessages.cs index 6a1c75da8d..290ea25a27 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/PubSubMessages.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/PubSubMessages.cs @@ -2,6 +2,6 @@ public static class PubSubMessages { - public const string PROFILE_UPDATED = "PROFILEUPDATED"; - public const string SHOW_MESSAGE = "SHOWMESSAGE"; + public const string PROFILE_UPDATED = nameof(PROFILE_UPDATED); + public const string SHOW_MESSAGE = nameof(SHOW_MESSAGE); } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/appsettings.json b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/appsettings.json index 1205647c49..f45a2d2751 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/appsettings.json +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/appsettings.json @@ -1,3 +1,3 @@ { - "ApiServerAddress": "http://localhost:5030/api/" // You can also use relative urls such as api/ for Blazor Server and WebAssembly + "ApiServerAddress": "http://localhost:5030/" // You can also use relative urls such as / for Blazor Server and WebAssembly } diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/compilerconfig.json b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/compilerconfig.json index cda36151e8..1c3c3d9369 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/compilerconfig.json +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/compilerconfig.json @@ -153,8 +153,8 @@ "options": { "sourceMap": false } }, { - "outputFile": "Components/Pages/Dashboard/ProductsCountPerCategotyWidget.razor.css", - "inputFile": "Components/Pages/Dashboard/ProductsCountPerCategotyWidget.razor.scss", + "outputFile": "Components/Pages/Dashboard/ProductsCountPerCategoryWidget.razor.css", + "inputFile": "Components/Pages/Dashboard/ProductsCountPerCategoryWidget.razor.scss", "minify": { "enabled": false }, "options": { "sourceMap": false } }, diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj index 1d1ff128a6..ed511f1dc2 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Boilerplate.Client.Maui.csproj @@ -84,14 +84,14 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cs index 698b37ddf5..5de035b834 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cs @@ -1,7 +1,6 @@ //-:cnd:noEmit using System.Reflection; -using Boilerplate.Client.Core.Services.HttpMessageHandlers; using Boilerplate.Client.Maui.Services; namespace Boilerplate.Client.Maui; @@ -10,6 +9,8 @@ public static class MauiProgram { public static MauiApp CreateMauiApp() { + AppRenderMode.IsBlazorHybrid = true; + var builder = MauiApp.CreateBuilder(); var assembly = typeof(MainLayout).GetTypeInfo().Assembly; @@ -30,7 +31,7 @@ public static MauiApp CreateMauiApp() services.AddTransient(sp => { - var handler = sp.GetRequiredService(); + var handler = sp.GetRequiredKeyedService("DefaultMessageHandler"); HttpClient httpClient = new(handler) { BaseAddress = apiServerAddress diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/wwwroot/index.html b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/wwwroot/index.html index 5bec0ff649..82eab231fe 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/wwwroot/index.html +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/wwwroot/index.html @@ -6,7 +6,7 @@ - + @@ -117,7 +117,7 @@ - +
diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Boilerplate.Client.Web.csproj b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Boilerplate.Client.Web.csproj index 3dfaf2cce0..9297c8acf2 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Boilerplate.Client.Web.csproj +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Boilerplate.Client.Web.csproj @@ -29,12 +29,12 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Program.cs b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Program.cs index 359157b789..e2e88642c6 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Program.cs +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Program.cs @@ -1,5 +1,4 @@ -using Boilerplate.Client.Core.Services.HttpMessageHandlers; -using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; var builder = WebAssemblyHostBuilder.CreateDefault(args); @@ -12,15 +11,16 @@ apiServerAddress = new Uri($"{builder.HostEnvironment.BaseAddress}{apiServerAddress}"); } -builder.Services.AddTransient(sp => new HttpClient(sp.GetRequiredService()) { BaseAddress = apiServerAddress }); +builder.Services.AddTransient(sp => new HttpClient(sp.GetRequiredKeyedService("DefaultMessageHandler")) { BaseAddress = apiServerAddress }); builder.Services.AddClientWebServices(); var host = builder.Build(); -#if MultilingualEnabled -var culture = await host.Services.GetRequiredService().GetItem("Culture"); -CultureInfoManager.SetCurrentCulture(culture); -#endif +if (AppRenderMode.MultilingualEnabled) +{ + var culture = await host.Services.GetRequiredService().GetItem("Culture"); + CultureInfoManager.SetCurrentCulture(culture); +} await host.RunAsync(); diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/wwwroot/service-worker.published.js b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/wwwroot/service-worker.published.js index c43dbab41d..7ebe7b4d17 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/wwwroot/service-worker.published.js +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/wwwroot/service-worker.published.js @@ -1,4 +1,4 @@ -// bit version: 8.2.0 +// bit version: 8.3.0 // https://github.com/bitfoundation/bitplatform/tree/develop/src/Bswup self.assetsInclude = []; diff --git a/src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Build.props b/src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Build.props index 5cde7401c9..e0ee29c9b4 100644 --- a/src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Build.props +++ b/src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Build.props @@ -1,4 +1,4 @@ - + @@ -44,9 +44,9 @@ - + diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Bit.Websites.Careers.Client.csproj b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Bit.Websites.Careers.Client.csproj index 8a7564360d..062081947f 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Bit.Websites.Careers.Client.csproj +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Bit.Websites.Careers.Client.csproj @@ -24,14 +24,14 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Bit.Websites.Careers.Server.csproj b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Bit.Websites.Careers.Server.csproj index aa291e6947..f6aaddea3d 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Bit.Websites.Careers.Server.csproj +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Bit.Websites.Careers.Server.csproj @@ -9,11 +9,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/App.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/App.razor index 7767b790fe..9de383460a 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/App.razor +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/App.razor @@ -17,7 +17,7 @@ - + diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/Script.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/Script.razor index 9cdcddcd48..9394c9f44c 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/Script.razor +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/Script.razor @@ -4,15 +4,25 @@ @code { [Parameter] public bool AppendVersion { get; set; } = true; - [Parameter] public required string Src { get; set; } = ""; + [Parameter] public string? Src { get; set; } + [Parameter] public RenderFragment? ChildContent { get; set; } [Parameter(CaptureUnmatchedValues = true)] public Dictionary AdditionalAttributes { get; set; } = default!; - private string src = ""; + private string? src; protected override void OnInitialized() { - src = AppendVersion ? _fileVersionProvider.AddFileVersionToPath(_httpContextAccessor.HttpContext!.Request.PathBase, Src) : Src; + src = (Src is not null && AppendVersion) ? _fileVersionProvider.AddFileVersionToPath(_httpContextAccessor.HttpContext!.Request.PathBase, Src) : Src; } } - \ No newline at end of file +@if (src is not null) +{ + +} +else +{ + +} \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Bit.Websites.Careers.Shared.csproj b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Bit.Websites.Careers.Shared.csproj index 1d3b314093..074827a5f9 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Bit.Websites.Careers.Shared.csproj +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Bit.Websites.Careers.Shared.csproj @@ -6,11 +6,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/IServiceCollectionExtensions.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/IServiceCollectionExtensions.cs index c1a3e9eb7c..d68400efc6 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/IServiceCollectionExtensions.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/IServiceCollectionExtensions.cs @@ -6,7 +6,7 @@ public static class IServiceCollectionExtensions { public static IServiceCollection AddSharedServices(this IServiceCollection services) { - // Services being registered here can get injected everywhere (Api, Web, Android, iOS, Windows, macOS and Linux) + // Services being registered here can get injected everywhere (Api, Web, Android, iOS, Windows and macOS) services.AddTransient(); diff --git a/src/Websites/Careers/src/Directory.Build.props b/src/Websites/Careers/src/Directory.Build.props index 42b137bb7b..14134005d2 100644 --- a/src/Websites/Careers/src/Directory.Build.props +++ b/src/Websites/Careers/src/Directory.Build.props @@ -1,4 +1,4 @@ - + 12.0 diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Bit.Websites.Platform.Client.csproj b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Bit.Websites.Platform.Client.csproj index df921bee3b..a43fc4cec3 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Bit.Websites.Platform.Client.csproj +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Bit.Websites.Platform.Client.csproj @@ -24,14 +24,14 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Extensions/IJSRuntimeExtension.cs b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Extensions/IJSRuntimeExtension.cs index 198966fcd7..bc0eb4a990 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Extensions/IJSRuntimeExtension.cs +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Extensions/IJSRuntimeExtension.cs @@ -7,13 +7,8 @@ public static async Task ToggleBodyOverflow(this IJSRuntime jsRuntime, bool isNa await jsRuntime.InvokeVoidAsync("toggleBodyOverflow", isNavOpen); } - public static async Task GoBack(this IJSRuntime jsRuntime) + public static async Task ScrollElementIntoView(this IJSRuntime jsRuntime, ElementReference element) { - await jsRuntime.InvokeVoidAsync("App.goBack"); - } - - public static async Task ApplyBodyElementClasses(this IJSRuntime jsRuntime, List cssClasses, Dictionary cssVariables) - { - await jsRuntime.InvokeVoidAsync("App.applyBodyElementClasses", cssClasses, cssVariables); + await jsRuntime.InvokeVoidAsync("scrollElementIntoView", element); } } diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/HomePage.razor b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/HomePage.razor index c45ca26058..2c7a8a894f 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/HomePage.razor +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/HomePage.razor @@ -15,7 +15,7 @@

- + Quick start   @@ -87,14 +87,10 @@
- - Todo sample - + Todo sample
- - TodoTemplate - + Todo sample
The Todo sample is built with bit platform Boilerplate project template, ASP.NET Core, Identity, Web API, and EF Core and Blazor. @@ -102,18 +98,14 @@
- - AdminPanel sample - + AdminPanel sample
- - AdminPanel - + AdminPanel sample
The AdminPanel sample is built with bit platform Boilerplate project template, ASP.NET Core, Identity, Web API, and EF Core and Blazor. @@ -121,7 +113,7 @@
@@ -219,12 +211,12 @@
-
+
Quick start Quickly start with the bit platform products & tools
- Quick start + Join for free
@@ -104,7 +104,7 @@
- ShowBuyModal("Paid", "€1200")))>Buy + ShowBuyModal()))>Contact sales @@ -117,30 +117,32 @@ { } else { - + - Buy @selectedPackageTitle Package - @selectedPackagePrice + Contact sale team + Buying the commercial package +
+ Placeholder="name@company.com" /> + Placeholder="Describe your needs" /> Send diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/PricingPage.razor.cs b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/PricingPage.razor.cs index 1d34275c6a..b9e1b80672 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/PricingPage.razor.cs +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/PricingPage.razor.cs @@ -7,29 +7,19 @@ public partial class PricingPage private bool isSent; private bool isSending; private bool isBuyModalOpen; - private string selectedPackageTitle = string.Empty; - private string selectedPackagePrice = string.Empty; - private BuyPackageDto buyPackageModel = new(); - - private void ShowBuyModal(string title, string price) + private void ShowBuyModal() { - selectedPackageTitle = title; - selectedPackagePrice = price; - buyPackageModel.SalePackageTitle = title; isBuyModalOpen = true; } private void CloseModal() { - isBuyModalOpen = false; isSent = false; - - buyPackageModel.Email = ""; - buyPackageModel.Message = ""; - buyPackageModel.SalePackageTitle = ""; + isBuyModalOpen = false; + buyPackageModel = new(); } private async Task SendMessage() diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/PricingPage.razor.scss b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/PricingPage.razor.scss index efd681d324..942d739c24 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/PricingPage.razor.scss +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/PricingPage.razor.scss @@ -129,8 +129,8 @@ } .form { + padding: 3rem; text-align: center; - padding: rem2(48px) rem2(32px); } .modal-text-field { diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/MultilingualismPage.razor b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/MultilingualismPage.razor index 0535ac8c10..587124ed00 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/MultilingualismPage.razor +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/MultilingualismPage.razor @@ -26,7 +26,7 @@
You also can customize the details of each culture in the CreateCultureInfo method, and the implementations of the bit platform templates - will apply these changes in all of the supported platforms: Web, Android, iOS, macOS, Windows, Linux and even in Pre-Rendering. + will apply these changes in all of the supported platforms: Web, Android, iOS, macOS, Windows and even in Pre-Rendering.
The required translations of the DTO's Validation Annotations will come from the values inside the AppStrings.resx file by default. diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/OverviewPage.razor b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/OverviewPage.razor index 7d9b74455d..a012c7badd 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/OverviewPage.razor +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/OverviewPage.razor @@ -15,7 +15,7 @@
- AdminPanel + AdminPanel sample
Demo
@@ -42,7 +42,7 @@
- TodoTemplate + Todo sample
Demo
diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/ProjectStructurePage.razor b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/ProjectStructurePage.razor index a3208ff3c9..9f7a8e6bfc 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/ProjectStructurePage.razor +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/ProjectStructurePage.razor @@ -21,7 +21,7 @@ The VS solution prepared by the bit project templates has 6 Projects.
- TodoTemplate solution + Boilerplate solution
diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Scripts/app.ts b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Scripts/app.ts index 598ec03123..214a4566db 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Scripts/app.ts +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Scripts/app.ts @@ -1,6 +1,4 @@ -//declare var hljs: any; - -function toggleBodyOverflow(isMenuOpen: boolean) { +function toggleBodyOverflow(isMenuOpen: boolean) { if (window.innerWidth <= 900) { if (isMenuOpen) { document.body.style.overflow = "hidden"; @@ -10,21 +8,14 @@ function toggleBodyOverflow(isMenuOpen: boolean) { } } -function RegisterOnScrollToChangeGettingStartedSideRailStyle(element: any) { - window.addEventListener('scroll', (event) => { - if (document.documentElement.scrollTop >= 500) { - element.classList.add("fixed-getting-started-side-rail-section"); - } - else { - element.classList.remove("fixed-getting-started-side-rail-section"); - } - }); -} - function goToTop() { window.scrollTo({ top: 0 }); } +function scrollElementIntoView(element: HTMLElement) { + element?.scrollIntoView(); +} + declare class BitTheme { static init(options: any): void; }; BitTheme.init({ diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/Footer.razor b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/Footer.razor index ffb68d3a58..48b9360ce0 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/Footer.razor +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/Footer.razor @@ -11,8 +11,8 @@