├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── publish-nuget.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── PRIVACY.md ├── README.md ├── SECURITY.md ├── ShadUI.sln ├── docs ├── demo-01.gif ├── demo-02.gif ├── demo-03.gif ├── demo-04.gif └── hero.png ├── icon.png └── src ├── ShadUI.Demo ├── App.axaml ├── App.axaml.cs ├── Assets │ ├── Fonts │ │ ├── JetBrainsMono.ttf │ │ ├── Manrope-Bold.ttf │ │ ├── Manrope-ExtraBold.ttf │ │ ├── Manrope-ExtraLight.ttf │ │ ├── Manrope-Light.ttf │ │ ├── Manrope-Medium.ttf │ │ ├── Manrope-Regular.ttf │ │ └── Manrope-SemiBold.ttf │ ├── Sales │ │ ├── 01.png │ │ ├── 02.png │ │ ├── 03.png │ │ ├── 04.png │ │ └── 05.png │ ├── favicon.ico │ └── user.png ├── Controls │ ├── CodeTextBlock.axaml │ ├── CodeTextBlock.axaml.cs │ ├── ControlBlock.axaml │ ├── ControlBlock.axaml.cs │ ├── Dashboard │ │ ├── OverviewCard.axaml │ │ └── OverviewCard.cs │ ├── Index.axaml │ ├── ThemeColor.axaml │ ├── ThemeColor.axaml.cs │ ├── ThemeCornerRadius.axaml │ └── ThemeCornerRadius.axaml.cs ├── Converters │ ├── BooleanToNullOrStringConverter.cs │ ├── BrushConverters.cs │ ├── CornerRadiusConverters.cs │ ├── DateOnlyToDateTimeOffsetConverter.cs │ ├── StringConverters.cs │ ├── ThemeModeConverters.cs │ └── TimeOnlyToTimeSpanConverter.cs ├── CustomIcons.cs ├── Extensions.cs ├── IUtilitiesModule.cs ├── Program.cs ├── ServiceProvider.cs ├── ShadUI.Demo.csproj ├── Styles │ ├── Index.axaml │ ├── Menu.axaml │ ├── Tooltip.axaml │ └── Window.axaml ├── Themes │ ├── Dark.axaml │ └── Light.axaml ├── TrayMenuHelper.cs ├── Validators │ ├── DateValidationAttributes.cs │ ├── EmailValidationAttribute.cs │ ├── IsMatchWithAttribute.cs │ └── TimeValidationAttributes.cs ├── ViewModels │ ├── AboutViewModel.cs │ ├── AvatarsViewModel.cs │ ├── ButtonsViewModel.cs │ ├── CardsViewModel.cs │ ├── CheckBoxesViewModel.cs │ ├── ComboBoxesViewModel.cs │ ├── DashboardViewModel.cs │ ├── DataGridViewModel.cs │ ├── DateViewModel.cs │ ├── DialogsViewModel.cs │ ├── InputViewModel.cs │ ├── LoginViewModel.cs │ ├── MainWindowViewModel.cs │ ├── MenuViewModel.cs │ ├── MiscellaneousViewModel.cs │ ├── SlidersViewModel.cs │ ├── SwitchViewModel.cs │ ├── TabsViewModel.cs │ ├── ThemeViewModel.cs │ ├── TimeViewModel.cs │ ├── ToastsViewModel.cs │ ├── TogglesViewModel.cs │ ├── ToolTipViewModel.cs │ ├── TypographyViewModel.cs │ └── ViewModelBase.cs ├── Views │ ├── AboutContent.axaml │ ├── AboutContent.axaml.cs │ ├── AvatarPage.axaml │ ├── AvatarPage.axaml.cs │ ├── ButtonsPage.axaml │ ├── ButtonsPage.axaml.cs │ ├── CardsPage.axaml │ ├── CardsPage.axaml.cs │ ├── CheckBoxesPage.axaml │ ├── CheckBoxesPage.axaml.cs │ ├── ComboBoxesPage.axaml │ ├── ComboBoxesPage.axaml.cs │ ├── DashboardPage.axaml │ ├── DashboardPage.axaml.cs │ ├── DataGridPage.axaml │ ├── DataGridPage.axaml.cs │ ├── DatePage.axaml │ ├── DatePage.axaml.cs │ ├── DialogsPage.axaml │ ├── DialogsPage.axaml.cs │ ├── InputPage.axaml │ ├── InputPage.axaml.cs │ ├── LoginContent.axaml │ ├── LoginContent.axaml.cs │ ├── MainWindow.axaml │ ├── MainWindow.axaml.cs │ ├── MenuViewPage.axaml │ ├── MenuViewPage.axaml.cs │ ├── MiscellaneousPage.axaml │ ├── MiscellaneousPage.axaml.cs │ ├── PageDataTemplates.axaml │ ├── SlidersPage.axaml │ ├── SlidersPage.axaml.cs │ ├── SwitchPage.axaml │ ├── SwitchPage.axaml.cs │ ├── TabsPage.axaml │ ├── TabsPage.axaml.cs │ ├── ThemePage.axaml │ ├── ThemePage.axaml.cs │ ├── TimePage.axaml │ ├── TimePage.axaml.cs │ ├── ToastsPage.axaml │ ├── ToastsPage.axaml.cs │ ├── TogglePage.axaml │ ├── TogglePage.axaml.cs │ ├── ToolTipPage.axaml │ ├── ToolTipPage.axaml.cs │ ├── TypographyPage.axaml │ └── TypographyPage.axaml.cs └── app.manifest ├── ShadUI.Package ├── Images │ ├── LockScreenLogo.scale-200.png │ ├── SplashScreen.scale-200.png │ ├── Square150x150Logo.scale-200.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── StoreLogo.png │ └── Wide310x150Logo.scale-200.png ├── Package.appxmanifest └── ShadUI.Package.wapproj └── ShadUI ├── Breakpoints ├── Breakpoint.cs ├── BreakpointRange.cs ├── View.axaml ├── View.axaml.cs └── ViewPort.cs ├── Contents └── Icons.cs ├── Controls ├── AutoCompleteBox.axaml ├── Avatar.axaml ├── Avatar.axaml.cs ├── BusyArea.axaml ├── BusyArea.axaml.cs ├── Button.axaml ├── Calendar.axaml ├── CalendarButton.axaml ├── CalendarDatePicker.axaml ├── CalendarDayButton.axaml ├── CalendarItem.axaml ├── Card.axaml ├── Card.axaml.cs ├── CardDescription.axaml ├── CardDescription.axaml.cs ├── CardTitle.axaml ├── CardTitle.axaml.cs ├── CheckBox.axaml ├── ComboBox.axaml ├── ComboBoxItem.axaml ├── Constants.axaml ├── DataGrid.axaml ├── DataValidationErrors.axaml ├── DateInput.axaml ├── DateInput.axaml.cs ├── Index.axaml ├── Loading.axaml ├── Loading.axaml.cs ├── Menu.axaml ├── MenuFlyoutPresenter.axaml ├── MenuItem.axaml ├── SelectableTextBlock.axaml ├── SidebarMenu.axaml ├── SidebarMenu.axaml.cs ├── SidebarMenuItem.axaml ├── SidebarMenuItem.axaml.cs ├── SimpleDropdown.axaml ├── SimpleDropdown.axaml.cs ├── Skeleton.axaml ├── Skeleton.axaml.cs ├── Slider.axaml ├── Switch.axaml ├── TabControl.axaml ├── TabItem.axaml ├── TextBox.axaml ├── TimeInput.axaml ├── TimeInput.axaml.cs ├── TimePicker.axaml ├── Toggle.axaml ├── ToolTip.axaml ├── Window.axaml └── Window.axaml.cs ├── Converters ├── BoolToWidthProgressConverter.cs ├── BooleanConverters.cs ├── ClockIdentifierToIsVisibleConverter.cs ├── CornerRadiusConverter.cs ├── DialogButtonStyleToButtonClassConverter.cs ├── PopupMaxDropDownHeightConverter.cs ├── PopupMinWidthConverter.cs ├── SideMenuScrollerToVisibilityBool.cs ├── SidebarMenuScrollerToOpacityMask.cs ├── SidebarMenuScrollerToVisibilityBool.cs ├── WidthToVisibilityConverter.cs ├── WindowBackgroundToCornerRadiusConverter.cs └── WindowBackgroundToMarginConverter.cs ├── Dialogs ├── CloseDialogOptions.cs ├── DialogBuilder.cs ├── DialogBuilderExtensions.cs ├── DialogButtonStyle.cs ├── DialogHost.axaml ├── DialogHost.axaml.cs ├── DialogManager.cs ├── DialogOptions.cs ├── SimpleDialog.axaml ├── SimpleDialog.axaml.cs └── SimpleDialogBuilder.cs ├── Enums └── LoadingStyle.cs ├── Extensions ├── Application.cs ├── ButtonAssist.cs ├── ControlAssist.cs ├── ElementAssist.cs ├── ItemsControlAssist.cs ├── ItemsPresenterAssist.cs ├── MenuItemAssist.cs ├── OnScreenKeyboard.cs ├── Scrollable.cs ├── StackPanelAssist.cs ├── TextBoxAssist.cs └── ToggleSwitchAssist.cs ├── Input └── SmartKeyBinding.cs ├── ShadUI.csproj ├── Styles ├── DataGrid.axaml ├── Index.axaml ├── Loading.axaml ├── ScrollBar.axaml ├── ScrollViewer.axaml ├── SelectableTextBlock.axaml ├── Separator.axaml ├── SimpleDropdown.axaml └── TextBlock.axaml ├── Themes ├── Dark.axaml ├── Light.axaml ├── ShadTheme.axaml ├── ShadTheme.axaml.cs ├── ThemeColors.cs ├── ThemeMode.cs └── ThemeWatcher.cs ├── Toasts ├── Notification.cs ├── Toast.axaml ├── Toast.axaml.cs ├── ToastBuilder.cs ├── ToastBuilderExtensions.cs ├── ToastHost.axaml ├── ToastHost.axaml.cs ├── ToastManager.cs └── ToastPosition.cs └── Utilities ├── ControlAnimationHelper.cs └── DataTemplateInclude.cs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: accountech 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Version [e.g. 22] 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/publish-nuget.yml: -------------------------------------------------------------------------------- 1 | name: Publish NuGet Package 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' # Triggers only on version tags like v1.0.0 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v2 15 | with: 16 | fetch-depth: 0 # Required for MinVer 17 | 18 | - name: Install SSL dependencies 19 | run: | 20 | sudo apt-get update 21 | sudo apt-get install -y libssl-dev 22 | 23 | - name: Setup .NET 24 | uses: actions/setup-dotnet@v3 25 | with: 26 | dotnet-version: '9.0.x' # Updated to a more recent .NET version 27 | 28 | - name: Install MinVer 29 | run: dotnet tool install --global minver-cli 30 | 31 | - name: Restore dependencies 32 | run: dotnet restore src/ShadUI/ShadUI.csproj 33 | env: 34 | DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: true 35 | 36 | - name: Build 37 | run: dotnet build src/ShadUI/ShadUI.csproj --configuration Release --no-restore 38 | 39 | - name: Increment version 40 | run: | 41 | VERSION=$(minver) 42 | sed -i "s/.*<\/Version>/${VERSION}<\/Version>/" src/ShadUI/ShadUI.csproj 43 | 44 | - name: Pack 45 | run: dotnet pack src/ShadUI/ShadUI.csproj --configuration Release --no-build --output ./output 46 | 47 | - name: Publish to NuGet 48 | env: 49 | NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} 50 | run: dotnet nuget push ./output/*.nupkg --api-key $NUGET_API_KEY --source https://api.nuget.org/v3/index.json 51 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project! We welcome contributions from everyone. 4 | 5 | ## Code of Conduct 6 | 7 | This project and everyone participating in it is governed by our [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to accntech.dev@gmail.com. 8 | 9 | ## How to Contribute 10 | 11 | ### Reporting Issues 12 | 13 | - Before creating an issue, please check if a similar issue already exists 14 | - Provide a clear and descriptive title 15 | - Include steps to reproduce the issue 16 | - Describe the expected behavior and what actually happened 17 | - Include any relevant screenshots or error messages 18 | 19 | ### Pull Requests 20 | 21 | 1. Fork the repository and create your branch from `main` 22 | 2. If you've added code that should be tested, add tests 23 | 3. Ensure the test suite passes 24 | 4. Make sure your code follows the existing code style 25 | 5. Write a clear and descriptive commit message, please follow the commit message convention 26 | 6. Update documentation as needed 27 | 28 | ### Development Process 29 | 30 | 1. Create an issue describing the change you want to make 31 | 2. Fork the repository 32 | 3. Create a feature branch 33 | 4. Make your changes 34 | 5. Submit a pull request 35 | 36 | ### Coding Standards 37 | 38 | - Follow the existing code style 39 | - Write clear, readable, and maintainable code 40 | - Comment your code when necessary 41 | - Keep your changes focused and atomic 42 | 43 | ### Documentation 44 | 45 | - Update the README.md if needed 46 | - Add inline documentation for new functions or complex logic 47 | - Update any relevant documentation files 48 | 49 | ## Questions? 50 | 51 | If you have any questions, feel free to create an issue or reach out to the maintainers at accntech.dev@gmail.com. 52 | 53 | Thank you for contributing! 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Accountech Business Management Services 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PRIVACY.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy for ShadUI 2 | 3 | ## Overview 4 | 5 | ShadUI is an open-source UI component library for Avalonia. This privacy policy explains our practices regarding the collection, use, and disclosure of information when you use our library. 6 | 7 | ## Information Collection 8 | 9 | ### No Direct Data Collection 10 | 11 | ShadUI is a client-side UI component library that does not directly collect, store, or transmit any personal information. The library operates entirely within your application's environment. 12 | 13 | ### Usage Analytics 14 | 15 | - We do not include any tracking mechanisms or analytics in the library itself 16 | - We do not collect usage statistics about how you implement or use the components 17 | - No telemetry data is gathered about component performance or usage patterns 18 | 19 | ### Third-Party Dependencies 20 | 21 | While ShadUI itself does not collect data, it uses third-party dependencies (such as Avalonia). Users should review the privacy policies of these dependencies separately. 22 | 23 | ## Data Storage 24 | 25 | - ShadUI does not store any user data 26 | - Any data displayed through ShadUI components is managed entirely by your application 27 | - No cache or local storage is maintained by the library 28 | 29 | ## Updates and Changes 30 | 31 | We may update this Privacy Policy from time to time. We will notify users of any changes by updating the "Last updated" date at the top of this policy. 32 | 33 | ## Contact 34 | 35 | If you have any questions about this Privacy Policy, please create an issue in our GitHub repository. 36 | 37 | ## Compliance 38 | 39 | This library is designed to be compliant with: 40 | 41 | - General Data Protection Regulation (GDPR) 42 | - California Consumer Privacy Act (CCPA) 43 | - Other applicable data protection laws 44 | 45 | ## Security 46 | 47 | While ShadUI does not handle data directly, we maintain secure development practices and regularly update dependencies to patch any security vulnerabilities. 48 | 49 | ## Children's Privacy 50 | 51 | ShadUI is a development library and is not directed towards children. We do not knowingly collect any personal information from children under 13. 52 | 53 | ## Changes to This Privacy Policy 54 | 55 | We may update our Privacy Policy from time to time. We will notify you of any changes by posting the new Privacy Policy on this page and updating the "Last updated" date. 56 | 57 | ## Your Rights 58 | 59 | Since ShadUI does not collect personal data, there are no specific user rights to address. However, we remain committed to transparency in our practices and will promptly address any privacy concerns raised by our users. 60 | 61 | Last updated: February 03, 2025 62 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | The following versions of ShadUI are currently being supported with security updates: 6 | 7 | | Version | Supported | 8 | |---------| --------- | 9 | | 0.0.4 | ✅ | 10 | | 0.0.5 | ✅ | 11 | | 0.0.6 | ✅ | 12 | 13 | ## Reporting a Vulnerability 14 | 15 | We take the security of ShadUI seriously. If you believe you have found a security vulnerability, please report it to us following these steps: 16 | 17 | 1. **DO NOT** disclose the vulnerability publicly until it has been addressed by our team 18 | 2. Email your findings to accntech.dev@gmail.com 19 | 3. Provide detailed information about the vulnerability: 20 | - Description of the issue 21 | - Steps to reproduce 22 | - Affected versions 23 | - Any potential mitigations you've identified 24 | 25 | ### What to Expect 26 | 27 | - You will receive an acknowledgment of your report within 48 hours 28 | - We will investigate and provide an initial assessment within 7 days 29 | - We aim to release a fix for verified vulnerabilities within 30 days 30 | - We will keep you informed about the progress of your report 31 | 32 | ### Security Update Process 33 | 34 | Once a security issue is fixed: 35 | 36 | - We will release a security advisory 37 | - The fix will be released as a patch update 38 | - Users will be notified through our GitHub repository 39 | 40 | ## Security Best Practices 41 | 42 | When using ShadUI in your applications: 43 | 44 | 1. Always use the latest stable version 45 | 2. Regularly check for updates 46 | 3. Follow our security guidelines in the documentation 47 | 4. Keep your development environment and dependencies up to date 48 | 49 | ## Contact 50 | 51 | For any security-related questions, contact us at accntech.dev@gmail.com. 52 | -------------------------------------------------------------------------------- /docs/demo-01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/docs/demo-01.gif -------------------------------------------------------------------------------- /docs/demo-02.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/docs/demo-02.gif -------------------------------------------------------------------------------- /docs/demo-03.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/docs/demo-03.gif -------------------------------------------------------------------------------- /docs/demo-04.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/docs/demo-04.gif -------------------------------------------------------------------------------- /docs/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/docs/hero.png -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/icon.png -------------------------------------------------------------------------------- /src/ShadUI.Demo/App.axaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | avares://ShadUI.Demo/Assets/Fonts#Jetbrains 33 | avares://ShadUI.Demo/Assets/Fonts#Manrope 34 | 12 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/App.axaml.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Avalonia; 3 | using Avalonia.Controls.ApplicationLifetimes; 4 | using Avalonia.Data.Core.Plugins; 5 | using Avalonia.Markup.Xaml; 6 | using ShadUI.Demo.ViewModels; 7 | using ShadUI.Demo.Views; 8 | using ShadUI.Themes; 9 | 10 | namespace ShadUI.Demo; 11 | 12 | public class App : Application 13 | { 14 | public override void Initialize() 15 | { 16 | AvaloniaXamlLoader.Load(this); 17 | } 18 | 19 | public override void OnFrameworkInitializationCompleted() 20 | { 21 | if (ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) return; 22 | 23 | DisableAvaloniaDataAnnotationValidation(); 24 | 25 | var provider = new ServiceProvider().RegisterDialogs(); 26 | 27 | var themeWatcher = provider.GetService(); 28 | themeWatcher.Initialize(); 29 | var viewModel = provider.GetService(); 30 | viewModel.Initialize(); 31 | 32 | var mainWindow = new MainWindow { DataContext = viewModel }; 33 | this.RegisterTrayIconsEvents(mainWindow, viewModel); 34 | 35 | desktop.MainWindow = mainWindow; 36 | base.OnFrameworkInitializationCompleted(); 37 | } 38 | 39 | private void DisableAvaloniaDataAnnotationValidation() 40 | { 41 | // Get an array of plugins to remove 42 | var dataValidationPluginsToRemove = 43 | BindingPlugins.DataValidators.OfType().ToArray(); 44 | 45 | // remove each entry found 46 | foreach (var plugin in dataValidationPluginsToRemove) BindingPlugins.DataValidators.Remove(plugin); 47 | } 48 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/Fonts/JetBrainsMono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/Fonts/JetBrainsMono.ttf -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/Fonts/Manrope-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/Fonts/Manrope-Bold.ttf -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/Fonts/Manrope-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/Fonts/Manrope-ExtraBold.ttf -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/Fonts/Manrope-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/Fonts/Manrope-ExtraLight.ttf -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/Fonts/Manrope-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/Fonts/Manrope-Light.ttf -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/Fonts/Manrope-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/Fonts/Manrope-Medium.ttf -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/Fonts/Manrope-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/Fonts/Manrope-Regular.ttf -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/Fonts/Manrope-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/Fonts/Manrope-SemiBold.ttf -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/Sales/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/Sales/01.png -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/Sales/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/Sales/02.png -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/Sales/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/Sales/03.png -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/Sales/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/Sales/04.png -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/Sales/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/Sales/05.png -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/favicon.ico -------------------------------------------------------------------------------- /src/ShadUI.Demo/Assets/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Demo/Assets/user.png -------------------------------------------------------------------------------- /src/ShadUI.Demo/Controls/ControlBlock.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | 4 | namespace ShadUI.Demo.Controls; 5 | 6 | public class ControlBlock : ContentControl 7 | { 8 | public static readonly StyledProperty CodeProperty = 9 | AvaloniaProperty.Register(nameof(Code)); 10 | 11 | public string? Code 12 | { 13 | get => GetValue(CodeProperty); 14 | set => SetValue(CodeProperty, value); 15 | } 16 | 17 | public static readonly StyledProperty LanguageProperty = 18 | AvaloniaProperty.Register(nameof(Language), "xaml"); 19 | 20 | public string? Language 21 | { 22 | get => GetValue(LanguageProperty); 23 | set => SetValue(LanguageProperty, value); 24 | } 25 | 26 | public static readonly StyledProperty TitleProperty = 27 | AvaloniaProperty.Register(nameof(Title)); 28 | 29 | public string? Title 30 | { 31 | get => GetValue(TitleProperty); 32 | set => SetValue(TitleProperty, value); 33 | } 34 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Controls/Dashboard/OverviewCard.axaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 12 | 16 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 39 | 40 | 41 | 42 | 43 | 44 | 49 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 64 | 65 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Controls/Dashboard/OverviewCard.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.Primitives; 3 | 4 | namespace ShadUI.Demo.Controls.Dashboard; 5 | 6 | public class OverviewCard : TemplatedControl 7 | { 8 | public static readonly StyledProperty TitleProperty = 9 | AvaloniaProperty.Register(nameof(Title)); 10 | 11 | public string Title 12 | { 13 | get => GetValue(TitleProperty); 14 | set => SetValue(TitleProperty, value); 15 | } 16 | 17 | public static readonly StyledProperty ValueProperty = 18 | AvaloniaProperty.Register(nameof(Value)); 19 | 20 | public string Value 21 | { 22 | get => GetValue(ValueProperty); 23 | set => SetValue(ValueProperty, value); 24 | } 25 | 26 | public static readonly StyledProperty HintProperty = 27 | AvaloniaProperty.Register(nameof(Hint)); 28 | 29 | public string Hint 30 | { 31 | get => GetValue(HintProperty); 32 | set => SetValue(HintProperty, value); 33 | } 34 | 35 | public static readonly StyledProperty IconProperty = 36 | AvaloniaProperty.Register(nameof(Icon)); 37 | 38 | public object Icon 39 | { 40 | get => GetValue(IconProperty); 41 | set => SetValue(IconProperty, value); 42 | } 43 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Controls/Index.axaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Controls/ThemeColor.axaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 34 | 41 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Controls/ThemeColor.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.Primitives; 3 | 4 | namespace ShadUI.Demo.Controls; 5 | 6 | public class ThemeColor : TemplatedControl 7 | { 8 | public static readonly StyledProperty TitleProperty = AvaloniaProperty.Register( 9 | nameof(Title)); 10 | 11 | public string Title 12 | { 13 | get => GetValue(TitleProperty); 14 | set => SetValue(TitleProperty, value); 15 | } 16 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Controls/ThemeCornerRadius.axaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 37 | 44 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Controls/ThemeCornerRadius.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.Primitives; 3 | 4 | namespace ShadUI.Demo.Controls; 5 | 6 | public class ThemeCornerRadius : TemplatedControl 7 | { 8 | public static readonly StyledProperty TitleProperty = AvaloniaProperty.Register( 9 | nameof(Title)); 10 | 11 | public string Title 12 | { 13 | get => GetValue(TitleProperty); 14 | set => SetValue(TitleProperty, value); 15 | } 16 | 17 | public static readonly StyledProperty BoxWidthProperty = 18 | AvaloniaProperty.Register( 19 | nameof(BoxWidth)); 20 | 21 | public double BoxWidth 22 | { 23 | get => GetValue(BoxWidthProperty); 24 | set => SetValue(BoxWidthProperty, value); 25 | } 26 | 27 | public static readonly StyledProperty BoxHeightProperty = 28 | AvaloniaProperty.Register( 29 | nameof(BoxHeight)); 30 | 31 | public double BoxHeight 32 | { 33 | get => GetValue(BoxHeightProperty); 34 | set => SetValue(BoxHeightProperty, value); 35 | } 36 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Converters/BooleanToNullOrStringConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | 5 | namespace ShadUI.Demo.Converters; 6 | 7 | public class BooleanToNullOrStringConverter : IValueConverter 8 | { 9 | public static BooleanToNullOrStringConverter Instance = new(); 10 | 11 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 12 | { 13 | var stringValue = parameter?.ToString(); 14 | 15 | if (value is bool booleanValue) return booleanValue ? null : stringValue; 16 | 17 | return null; 18 | } 19 | 20 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => 21 | throw new NotImplementedException(); 22 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Converters/BrushConverters.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Data.Converters; 2 | using Avalonia.Media; 3 | using Avalonia.Media.Immutable; 4 | 5 | namespace ShadUI.Demo.Converters; 6 | 7 | public static class BrushConverters 8 | { 9 | public static readonly IValueConverter ToHex = 10 | new FuncValueConverter(b => 11 | { 12 | if (b is ImmutableSolidColorBrush solidColorBrush) 13 | { 14 | var color = solidColorBrush.Color; 15 | return $"#{color.A:X2}{color.R:X2}{color.G:X2}{color.B:X2}"; 16 | } 17 | 18 | return null; 19 | }); 20 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Converters/CornerRadiusConverters.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Data.Converters; 3 | 4 | namespace ShadUI.Demo.Converters; 5 | 6 | public static class CornerRadiusConverters 7 | { 8 | public static readonly IValueConverter ToPixel = 9 | new FuncValueConverter(cr => 10 | $"{cr.TopLeft} px"); 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Converters/DateOnlyToDateTimeOffsetConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | 5 | namespace ShadUI.Demo.Converters; 6 | 7 | public class DateOnlyToDateTimeOffsetConverter : IValueConverter 8 | { 9 | public static readonly DateOnlyToDateTimeOffsetConverter Instance = new(); 10 | 11 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => 12 | value is DateOnly dateOnly ? new DateTimeOffset(dateOnly.ToDateTime(TimeOnly.MinValue)) : null; 13 | 14 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => 15 | value is DateTimeOffset dateTimeOffset ? DateOnly.FromDateTime(dateTimeOffset.DateTime) : null; 16 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Converters/StringConverters.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Data.Converters; 2 | 3 | namespace ShadUI.Demo.Converters; 4 | 5 | public static class StringConverters 6 | { 7 | public static readonly IValueConverter IsEqual = 8 | new FuncValueConverter((x, y) => x!.Equals(y)); 9 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Converters/ThemeModeConverters.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Avalonia.Controls; 3 | using Avalonia.Data.Converters; 4 | using LucideAvalonia; 5 | using LucideAvalonia.Enum; 6 | using ShadUI.Themes; 7 | 8 | namespace ShadUI.Demo.Converters; 9 | 10 | public static class ThemeModeConverters 11 | { 12 | private static readonly Dictionary Icons = new() 13 | { 14 | { ThemeMode.System, new Lucide { Icon = LucideIconNames.SunMoon, StrokeThickness = 1.5, Width = 18, Height = 18 } }, 15 | { ThemeMode.Light, new Lucide { Icon = LucideIconNames.Sun, StrokeThickness = 1.5, Width = 18, Height = 18 } }, 16 | { ThemeMode.Dark, new Lucide { Icon = LucideIconNames.Moon, StrokeThickness = 1.5, Width = 14, Height = 14 } } 17 | }; 18 | 19 | public static readonly IValueConverter ToLucideIcon = 20 | new FuncValueConverter(mode => Icons.TryGetValue(mode, out var icon) ? icon : Icons[0]); 21 | } 22 | 23 | public static class WindowStateConverters 24 | { 25 | public static readonly IValueConverter IsFullScreen = 26 | new FuncValueConverter(state => 27 | { 28 | return state == WindowState.FullScreen; 29 | }); 30 | 31 | public static readonly IValueConverter IsNotFullScreen = 32 | new FuncValueConverter(state => 33 | { 34 | return state != WindowState.FullScreen; 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Converters/TimeOnlyToTimeSpanConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | 5 | namespace ShadUI.Demo.Converters; 6 | 7 | public class TimeOnlyToTimeSpanConverter : IValueConverter 8 | { 9 | public static readonly TimeOnlyToTimeSpanConverter Instance = new(); 10 | 11 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => 12 | value is TimeOnly timeOnly ? timeOnly.ToTimeSpan() : null; 13 | 14 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => 15 | value is TimeSpan timeSpan ? TimeOnly.FromTimeSpan(timeSpan) : null; 16 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/CustomIcons.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Media; 2 | using ShadUI.Contents; 3 | 4 | namespace ShadUI.Demo; 5 | 6 | public static class CustomIcons 7 | { 8 | public static StreamGeometry Github = Icons.Parse( 9 | "M96,7401 c5.5,0,10,4.6,10,10.3c0,4.2-2.5,8-6.3,9.5l0,0c0-0.6,0-1.5,0-2.5c0-0.5-0.1-1-0.2-1.3c1.9-0.5,4.5-1.8,4.5-6.3 c0-1.2-0.3-2.3-1-3.2c0.1-0.7,0.2-1.8-0.3-3.1l-0.2-0.4l-0.5-0.1c-0.1,0-0.3-0.1-0.6-0.1c-0.6,0-1.6,0.2-3,1.1 c-0.8-0.2-1.7-0.3-2.6-0.3c-0.9,0-1.7,0.1-2.6,0.3c-1.4-0.9-2.4-1.1-3-1.1c-0.3,0-0.5,0-0.6,0.1l-0.5,0.1l-0.2,0.4 c-0.5,1.3-0.4,2.5-0.3,3.1c-0.7,0.9-1,2-1,3.2c0,1.8,0.4,3.1,1.1,4.1c-0.2-0.1-0.4-0.1-0.6-0.1l0,0h0c-1.1,0-1.4,0.6-1.4,0.9 c0,0,0,0.1,0,0.1c-0.6-1.3-0.9-2.8-0.9-4.4C86,7405.6,90.5,7401,96,7401 M91.1,7416.5c0.5,0.2,0.9,0.4,1.4,0.5c0,0,0,0,0,0 c-0.1,0-0.3,0-0.4,0C91.8,7417.1,91.4,7417,91.1,7416.5 M87.8,7417.2L87.8,7417.2c0,0,0.4,0.2,0.7,0.9 C88.3,7417.8,88,7417.5,87.8,7417.2 M91.5,7420.4c0.2,0,0.4,0,0.6,0c0.1,0,0.1,0,0.2,0l0,0.2c0,0,0,0.1,0,0.1 C92,7420.7,91.7,7420.6,91.5,7420.4 M96,7400c-6.1,0-11,5-11,11.3c0,5,3.2,9.2,7.5,10.7c0.1,0,0.1,0,0.2,0c0.4,0,0.6-0.3,0.6-0.6 c0-0.3,0-1.2,0-2.1c-0.4,0.1-0.8,0.1-1.2,0.1c-2.1,0-2.5-1.5-2.5-1.5c-0.5-1.3-1.2-1.6-1.2-1.6c-1-0.7,0-0.7,0.1-0.7c0,0,0,0,0,0 c1.1,0.1,1.7,1.2,1.7,1.2c0.5,1,1.3,1.2,1.9,1.2c0.5,0,1-0.2,1.3-0.3c0.1-0.7,0.4-1.2,0.7-1.5c-2.4-0.3-5-1.3-5-5.6 c0-1.2,0.4-2.2,1.1-3c-0.1-0.3-0.5-1.4,0.1-3c0,0,0.1,0,0.2,0c0.4,0,1.3,0.2,2.8,1.2c0.9-0.2,1.8-0.4,2.8-0.4 c0.9,0,1.9,0.1,2.8,0.4c1.5-1,2.4-1.2,2.8-1.2c0.2,0,0.2,0,0.2,0c0.6,1.6,0.2,2.7,0.1,3c0.7,0.8,1.1,1.8,1.1,3 c0,4.3-2.6,5.3-5,5.6c0.4,0.4,0.7,1,0.7,2.1c0,1.5,0,2.7,0,3.1c0,0.3,0.2,0.6,0.6,0.6c0.1,0,0.1,0,0.2,0 c4.4-1.5,7.5-5.7,7.5-10.7C107,7405,102.1,7400,96,7400L96,7400z"); 10 | 11 | public static StreamGeometry Nuget = Icons.Parse( 12 | "M16.5,14c0.8,0,1.4,0.3,1.9,0.8c0.4,0.4,0.6,1.1,0.6,1.7c0,1.2-0.8,2.5-2.5,2.5c-0.8,0-1.4-0.3-1.9-0.8 c-0.4-0.4-0.6-1.1-0.6-1.7C14,15.3,14.8,14,16.5,14 M16.5,13c-4.7,0-4.7,7,0,7C21.2,20,21.2,13,16.5,13L16.5,13z M14.8,6L14.8,6 l2.4,0c2.7,0,4.8,2.2,4.8,4.8v6.3c0,1.3-0.5,2.5-1.4,3.4c-0.9,0.9-2.1,1.4-3.4,1.4h-6.3C8.2,22,6,19.8,6,17.2v-6.3 C6,8.2,8.2,6,10.8,6H14.8 M17.2,5h-6.3C7.6,5,5,7.6,5,10.8v6.3c0,3.2,2.6,5.8,5.8,5.8h6.3c1.5,0,3-0.6,4.1-1.7 c1.1-1.1,1.7-2.6,1.7-4.1v-6.3C23,7.6,20.4,5,17.2,5L17.2,5L17.2,5z M3,2c0.2,0,1,0,1,1S3.2,4,3,4S2,4,2,3S2.8,2,3,2 M3,1 C2,1,1,1.7,1,3s1,2,2,2s2-0.7,2-2S4,1,3,1L3,1z M10,9c0.2,0,1,0,1,1s-0.8,1-1,1s-1,0-1-1S9.8,9,10,9 M10,8c-1,0-2,0.7-2,2s1,2,2,2 s2-0.7,2-2S11,8,10,8L10,8z"); 13 | 14 | public static StreamGeometry License = Icons.Parse( 15 | "M22.9,15.7l-3-8c0-0.1,0-0.1-0.1-0.2H21c0.3,0,0.5-0.2,0.5-0.5S21.3,6.5,21,6.5h-2c-1.8,0-4.6-0.9-6.5-1.8V3 c0-0.3-0.2-0.5-0.5-0.5S11.5,2.7,11.5,3v1.7C9.6,5.6,6.8,6.5,5,6.5H3C2.7,6.5,2.5,6.7,2.5,7S2.7,7.5,3,7.5h1.1c0,0-0.1,0.1-0.1,0.2 l-3,8c-0.2,0.4,0,0.9,0.3,1.1C2.5,17.6,3.7,18,5,18s2.5-0.4,3.6-1.2c0.4-0.3,0.5-0.7,0.3-1.1l-3-8c0-0.1-0.1-0.1-0.1-0.2 c1.8-0.2,4-0.9,5.7-1.7v14.7H7c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5h10c0.3,0,0.5-0.2,0.5-0.5s-0.2-0.5-0.5-0.5h-4.5V5.8 c1.7,0.8,3.9,1.5,5.7,1.7c0,0.1-0.1,0.1-0.1,0.2l-3,8c-0.2,0.4,0,0.9,0.3,1.1c1,0.8,2.3,1.2,3.6,1.2s2.5-0.4,3.6-1.2 C23,16.5,23.1,16.1,22.9,15.7z M8,16c-0.9,0.7-1.9,1-3,1s-2.1-0.3-3-1l3-8L8,16z M19,17c-1.1,0-2.1-0.3-3-1l3-8l3,8 C21.1,16.7,20.1,17,19,17z"); 16 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Extensions.cs: -------------------------------------------------------------------------------- 1 | using ShadUI.Demo.ViewModels; 2 | using ShadUI.Demo.Views; 3 | using ShadUI.Dialogs; 4 | 5 | namespace ShadUI.Demo; 6 | 7 | public static class Extensions 8 | { 9 | public static ServiceProvider RegisterDialogs(this ServiceProvider service) 10 | { 11 | var dialogService = service.GetService(); 12 | dialogService.Register(); 13 | dialogService.Register(); 14 | 15 | return service; 16 | } 17 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/IUtilitiesModule.cs: -------------------------------------------------------------------------------- 1 | using Jab; 2 | using ShadUI.Dialogs; 3 | using ShadUI.Toasts; 4 | 5 | namespace ShadUI.Demo; 6 | 7 | [ServiceProviderModule] 8 | [Singleton] 9 | [Singleton] 10 | public interface IUtilitiesModule 11 | { 12 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia; 3 | 4 | namespace ShadUI.Demo; 5 | 6 | internal sealed class Program 7 | { 8 | // Initialization code. Don't use any Avalonia, third-party APIs or any 9 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized 10 | // yet and stuff might break. 11 | [STAThread] 12 | public static void Main(string[] args) => BuildAvaloniaApp() 13 | .StartWithClassicDesktopLifetime(args); 14 | 15 | // Avalonia configuration, don't remove; also used by visual designer. 16 | public static AppBuilder BuildAvaloniaApp() 17 | => AppBuilder.Configure() 18 | .UsePlatformDetect() 19 | .LogToTrace(); 20 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ServiceProvider.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Jab; 3 | using ShadUI.Demo.ViewModels; 4 | using ShadUI.Themes; 5 | 6 | namespace ShadUI.Demo; 7 | 8 | [ServiceProvider] 9 | [Transient] 10 | [Transient] 11 | [Transient] 12 | [Transient] 13 | [Transient] 14 | [Transient] 15 | [Transient] 16 | [Transient] 17 | [Transient] 18 | [Transient] 19 | [Transient] 20 | [Transient] 21 | [Transient] 22 | [Transient] 23 | [Transient] 24 | [Transient] 25 | [Transient] 26 | [Transient] 27 | [Transient] 28 | [Transient] 29 | [Transient] 30 | [Transient] 31 | [Transient] 32 | [Transient] 33 | [Import] 34 | [Singleton(typeof(ThemeWatcher), Factory = nameof(ThemeWatcherFactory))] 35 | public partial class ServiceProvider 36 | { 37 | public ThemeWatcher ThemeWatcherFactory() => new(Application.Current!); 38 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ShadUI.Demo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | WinExe 4 | net9.0 5 | enable 6 | 1.0.6 7 | true 8 | app.manifest 9 | true 10 | Assets\favicon.ico 11 | x64 12 | AnyCPU;x64 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | None 26 | All 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Styles/Index.axaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Styles/Menu.axaml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Styles/Tooltip.axaml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Styles/Window.axaml: -------------------------------------------------------------------------------- 1 |  5 | 8 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Themes/Dark.axaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | #FAFAFA 5 | #33FAFAFA 6 | #18181B 7 | 8 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Themes/Light.axaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | #E1E4E8 5 | #33E1E4E8 6 | #09090B 7 | 8 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/TrayMenuHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Avalonia; 4 | using Avalonia.Controls; 5 | using ShadUI.Demo.ViewModels; 6 | using ShadUI.Demo.Views; 7 | 8 | namespace ShadUI.Demo; 9 | 10 | public static class TrayMenuHelper 11 | { 12 | public static void RegisterTrayIconsEvents(this Application app, MainWindow window, MainWindowViewModel viewModel) 13 | { 14 | var trayIcons = TrayIcon.GetIcons(app); 15 | if (trayIcons is null || !trayIcons.Any()) return; 16 | var trayIcon = trayIcons[0]; 17 | 18 | if (trayIcon.Menu is null) return; 19 | 20 | var items = trayIcon.Menu.Items.OfType().ToList(); 21 | var openMenu = items.First(x => 22 | x.Header != null && x.Header.Contains("Open", StringComparison.CurrentCultureIgnoreCase)); 23 | var aboutMenu = items.First(x => 24 | x.Header != null && x.Header.Contains("About", StringComparison.CurrentCultureIgnoreCase)); 25 | var exitMenu = items.First(x => 26 | x.Header != null && x.Header.Contains("Exit", StringComparison.CurrentCultureIgnoreCase)); 27 | 28 | openMenu.Click += (_, _) => 29 | { 30 | if (window.WindowState == WindowState.Minimized) 31 | { 32 | window.RestoreWindowState(); 33 | window.Show(); 34 | } 35 | window.Activate(); 36 | }; 37 | 38 | aboutMenu.Click += (_, _) => 39 | { 40 | if (window.WindowState == WindowState.Minimized) 41 | { 42 | window.RestoreWindowState(); 43 | window.Show(); 44 | } 45 | window.Activate(); 46 | viewModel.ShowAboutCommand.Execute(null); 47 | }; 48 | 49 | exitMenu.Click += (_, _) => 50 | { 51 | if (window.WindowState == WindowState.Minimized) 52 | { 53 | window.RestoreWindowState(); 54 | window.Show(); 55 | } 56 | 57 | window.Activate(); 58 | viewModel.TryCloseCommand.Execute(null); 59 | }; 60 | } 61 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Validators/DateValidationAttributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace ShadUI.Demo.Validators; 5 | 6 | public sealed class StartDateValidationAttribute( 7 | string matchProperty, 8 | string errorMessage = "Start date must be before end date" 9 | ) : ValidationAttribute(errorMessage) 10 | { 11 | protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) 12 | { 13 | var instance = validationContext.ObjectInstance; 14 | var endDate = instance.GetType().GetProperty(matchProperty)?.GetValue(instance); 15 | 16 | if (endDate == null) 17 | return ValidationResult.Success; 18 | 19 | return ((DateOnly) value!).CompareTo(endDate) < 0 20 | ? ValidationResult.Success 21 | : new ValidationResult(ErrorMessage); 22 | } 23 | } 24 | 25 | public sealed class EndDateValidationAttribute( 26 | string matchProperty, 27 | string errorMessage = "End date must be after start date" 28 | ) : ValidationAttribute(errorMessage) 29 | { 30 | protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) 31 | { 32 | var instance = validationContext.ObjectInstance; 33 | var startDate = instance.GetType().GetProperty(matchProperty)?.GetValue(instance); 34 | 35 | if (startDate == null) 36 | return ValidationResult.Success; 37 | 38 | return ((DateOnly) value!).CompareTo(startDate) > 0 39 | ? ValidationResult.Success 40 | : new ValidationResult(ErrorMessage); 41 | } 42 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Validators/EmailValidationAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace ShadUI.Demo.Validators; 4 | 5 | public sealed class EmailValidationAttribute() : ValidationAttribute(DefaultErrorMessage) 6 | { 7 | private static readonly string DefaultErrorMessage = "Please enter a valid email address"; 8 | 9 | protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) 10 | { 11 | if (value is not string email) 12 | return new ValidationResult(ErrorMessage); 13 | 14 | if (string.IsNullOrWhiteSpace(email)) 15 | return new ValidationResult(ErrorMessage); 16 | 17 | var atIndex = email.IndexOf('@'); 18 | if (atIndex <= 0 || atIndex == email.Length - 1) 19 | return new ValidationResult(ErrorMessage); 20 | 21 | var dotIndex = email.IndexOf('.', atIndex); 22 | if (dotIndex == -1 || dotIndex == atIndex + 1 || dotIndex == email.Length - 1) 23 | return new ValidationResult(ErrorMessage); 24 | 25 | for (var i = 0; i < email.Length - 1; i++) 26 | if (email[i] == '.' && email[i + 1] == '.') 27 | return new ValidationResult(ErrorMessage); 28 | 29 | return ValidationResult.Success; 30 | } 31 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Validators/IsMatchWithAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace ShadUI.Demo.Validators; 5 | 6 | public sealed class IsMatchWithAttribute(string matchProperty, string errorMessage = "Not match") 7 | : ValidationAttribute(errorMessage) 8 | { 9 | protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) 10 | { 11 | var instance = validationContext.ObjectInstance; 12 | var otherValue = instance.GetType().GetProperty(matchProperty)?.GetValue(instance); 13 | 14 | return ((IComparable) value!).CompareTo(otherValue) == 0 15 | ? ValidationResult.Success 16 | : new ValidationResult(ErrorMessage); 17 | } 18 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Validators/TimeValidationAttributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace ShadUI.Demo.Validators; 5 | 6 | public sealed class StartTimeValidationAttribute( 7 | string matchProperty, 8 | string errorMessage = "Start time must be less than end time" 9 | ) : ValidationAttribute(errorMessage) 10 | { 11 | protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) 12 | { 13 | var instance = validationContext.ObjectInstance; 14 | var endTime = instance.GetType().GetProperty(matchProperty)?.GetValue(instance); 15 | 16 | if (endTime == null) 17 | return ValidationResult.Success; 18 | 19 | return ((TimeOnly) value!).CompareTo(endTime) < 0 20 | ? ValidationResult.Success 21 | : new ValidationResult(ErrorMessage); 22 | } 23 | } 24 | 25 | public sealed class EndTimeValidationAttribute( 26 | string matchProperty, 27 | string errorMessage = "End time must be greater than start time" 28 | ) : ValidationAttribute(errorMessage) 29 | { 30 | protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) 31 | { 32 | var instance = validationContext.ObjectInstance; 33 | var startTime = instance.GetType().GetProperty(matchProperty)?.GetValue(instance); 34 | 35 | if (startTime == null) 36 | return ValidationResult.Success; 37 | 38 | return ((TimeOnly) value!).CompareTo(startTime) > 0 39 | ? ValidationResult.Success 40 | : new ValidationResult(ErrorMessage); 41 | } 42 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ViewModels/AboutViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using CommunityToolkit.Mvvm.ComponentModel; 3 | using CommunityToolkit.Mvvm.Input; 4 | using ShadUI.Dialogs; 5 | 6 | namespace ShadUI.Demo.ViewModels; 7 | 8 | public sealed partial class AboutViewModel(DialogManager dialogManager) : ViewModelBase 9 | { 10 | [RelayCommand] 11 | private void Close() 12 | { 13 | dialogManager.Close(this); 14 | } 15 | 16 | [ObservableProperty] 17 | private string _appVersion = $"version {GetAssemblyVersion()}"; 18 | 19 | private static string GetAssemblyVersion() => 20 | Assembly.GetExecutingAssembly().GetName().Version?.ToString() 21 | ?? string.Empty; 22 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ViewModels/AvatarsViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace ShadUI.Demo.ViewModels; 4 | 5 | public sealed partial class AvatarsViewModel : ViewModelBase 6 | { 7 | [ObservableProperty] 8 | private string _usageCode = """ 9 | 10 | 11 | 12 | """; 13 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ViewModels/CardsViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace ShadUI.Demo.ViewModels; 4 | 5 | public sealed partial class CardsViewModel : ViewModelBase 6 | { 7 | [ObservableProperty] 8 | private string _usageCode = """ 9 | 10 | 11 | 12 | Create project 13 | Deploy your new project in one-click. 14 | 15 | 16 | 17 | 18 | 21 | 22 | Next.js 23 | React 24 | Vue.js 25 | Angular 26 | 27 | 28 | 29 | 30 | 31 | 34 | 37 | 38 | 39 | 40 | """; 41 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ViewModels/LoginViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using CommunityToolkit.Mvvm.Input; 3 | using ShadUI.Demo.Validators; 4 | using ShadUI.Dialogs; 5 | 6 | namespace ShadUI.Demo.ViewModels; 7 | 8 | public sealed partial class LoginViewModel(DialogManager dialogManager) : ViewModelBase 9 | { 10 | private string _email = string.Empty; 11 | 12 | [Required(ErrorMessage = "Email is required")] 13 | [EmailValidation] 14 | public string Email 15 | { 16 | get => _email; 17 | set => SetProperty(ref _email, value, true); 18 | } 19 | 20 | private string _password = string.Empty; 21 | 22 | [Required(ErrorMessage = "Password is required")] 23 | [MinLength(8, ErrorMessage = "Password must be at least 8 characters long")] 24 | public string Password 25 | { 26 | get => _password; 27 | set => SetProperty(ref _password, value, true); 28 | } 29 | 30 | private bool CanSubmit() => !HasErrors; 31 | 32 | public void Initialize() 33 | { 34 | Email = string.Empty; 35 | Password = string.Empty; 36 | 37 | ClearAllErrors(); 38 | } 39 | 40 | [RelayCommand(CanExecute = nameof(CanSubmit))] 41 | private void Submit() 42 | { 43 | ClearAllErrors(); 44 | ValidateAllProperties(); 45 | 46 | if (HasErrors) return; 47 | dialogManager.Close(this, new CloseDialogOptions { Success = true }); 48 | } 49 | 50 | [RelayCommand] 51 | private void Cancel() => dialogManager.Close(this); 52 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ViewModels/MiscellaneousViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using CommunityToolkit.Mvvm.ComponentModel; 3 | using CommunityToolkit.Mvvm.Input; 4 | 5 | namespace ShadUI.Demo.ViewModels; 6 | 7 | public sealed partial class MiscellaneousViewModel : ViewModelBase 8 | { 9 | [ObservableProperty] 10 | private bool _isBusy; 11 | 12 | [ObservableProperty] 13 | private string _busyAreaCode = """ 14 | 16 | 17 | 21 | 22 | 23 | 24 | """; 25 | 26 | [ObservableProperty] 27 | private string _skeletonCode = """ 28 | 29 | 31 | 32 | 33 | 34 | 35 | 36 | """; 37 | 38 | [RelayCommand] 39 | private async Task ToggleBusy() 40 | { 41 | IsBusy = true; 42 | await Task.Delay(3000); 43 | IsBusy = false; 44 | } 45 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ViewModels/SlidersViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace ShadUI.Demo.ViewModels; 4 | 5 | public sealed partial class SlidersViewModel : ViewModelBase 6 | { 7 | [ObservableProperty] 8 | private string _defaultSliderCode = """ 9 | 10 | 11 | 12 | """; 13 | 14 | [ObservableProperty] 15 | private string _disabledSliderCode = """ 16 | 17 | 18 | 19 | """; 20 | 21 | [ObservableProperty] 22 | private string _tickEnabledSliderCode = """ 23 | 24 | 25 | 26 | """; 27 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ViewModels/SwitchViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace ShadUI.Demo.ViewModels; 4 | 5 | public sealed partial class SwitchViewModel : ViewModelBase 6 | { 7 | [ObservableProperty] 8 | private string _enableCode = """ 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | """; 20 | 21 | [ObservableProperty] 22 | private string _disableCode = """ 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | """; 34 | 35 | [ObservableProperty] 36 | private string _rightAlignedCode = """ 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | """; 48 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ViewModels/TabsViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace ShadUI.Demo.ViewModels; 4 | 5 | public sealed partial class TabsViewModel : ViewModelBase 6 | { 7 | [ObservableProperty] 8 | private string _basicTabCode = """ 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Text="Taxing Laughter: The Joke Tax Chronicles" /> 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | """; 28 | 29 | [ObservableProperty] 30 | private string _h1Code = """ 31 | 33 | """; 34 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ViewModels/ThemeViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace ShadUI.Demo.ViewModels; 2 | 3 | public sealed class ThemeViewModel : ViewModelBase 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ViewModels/TogglesViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace ShadUI.Demo.ViewModels; 4 | 5 | public sealed partial class TogglesViewModel : ViewModelBase 6 | { 7 | [ObservableProperty] 8 | private string _default = """ 9 | 10 | 12 | 13 | """; 14 | 15 | [ObservableProperty] 16 | private string _outline = """ 17 | 18 | 20 | 21 | """; 22 | 23 | [ObservableProperty] 24 | private string _withText = """ 25 | 26 | 27 | 29 | 30 | 31 | 32 | """; 33 | 34 | [ObservableProperty] 35 | private string _disable = """ 36 | 38 | 40 | 41 | """; 42 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ViewModels/ToolTipViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace ShadUI.Demo.ViewModels; 4 | 5 | public sealed partial class ToolTipViewModel : ViewModelBase 6 | { 7 | [ObservableProperty] 8 | private string _usageCode = """ 9 | 10 | 16 | 17 | """; 18 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ViewModels/TypographyViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace ShadUI.Demo.ViewModels; 4 | 5 | public sealed partial class TypographyViewModel : ViewModelBase 6 | { 7 | [ObservableProperty] 8 | private string _h1Code = """ 9 | 11 | """; 12 | 13 | [ObservableProperty] 14 | private string _h2Code = """ 15 | 17 | """; 18 | 19 | [ObservableProperty] 20 | private string _h3Code = """ 21 | 23 | """; 24 | 25 | [ObservableProperty] 26 | private string _h4Code = """ 27 | 29 | """; 30 | 31 | [ObservableProperty] 32 | private string _pCode = """ 33 | 35 | """; 36 | 37 | [ObservableProperty] 38 | private string _leadCode = """ 39 | 41 | """; 42 | 43 | [ObservableProperty] 44 | private string _largeCode = """ 45 | 47 | """; 48 | 49 | [ObservableProperty] 50 | private string _smallCode = """ 51 | 53 | """; 54 | 55 | [ObservableProperty] 56 | private string _captionCode = """ 57 | 59 | """; 60 | 61 | [ObservableProperty] 62 | private string _mutedCode = """ 63 | 65 | """; 66 | 67 | [ObservableProperty] 68 | private string _errorCode = """ 69 | 71 | """; 72 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/ViewModels/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Linq; 7 | using System.Runtime.CompilerServices; 8 | using CommunityToolkit.Mvvm.ComponentModel; 9 | 10 | namespace ShadUI.Demo.ViewModels; 11 | 12 | public abstract class ViewModelBase : ObservableObject, INotifyDataErrorInfo 13 | { 14 | private readonly Dictionary> _errors = new(); 15 | 16 | public bool HasErrors => _errors.Count != 0; 17 | 18 | public event EventHandler? ErrorsChanged; 19 | 20 | public IEnumerable GetErrors(string? propertyName) 21 | { 22 | if (string.IsNullOrEmpty(propertyName)) 23 | return Array.Empty(); 24 | 25 | return _errors.TryGetValue(propertyName, out var errors) 26 | ? errors 27 | : Array.Empty(); 28 | } 29 | 30 | protected void SetProperty(ref T field, T value, bool validate = false, [CallerMemberName] string propertyName = null!) 31 | { 32 | if (EqualityComparer.Default.Equals(field, value)) return; 33 | 34 | field = value; 35 | OnPropertyChanged(propertyName); 36 | if (validate) ValidateProperty(value, propertyName); 37 | } 38 | 39 | protected void ValidateProperty(T value, string propertyName) 40 | { 41 | ClearErrors(propertyName); 42 | 43 | var validationContext = new ValidationContext(this) 44 | { 45 | MemberName = propertyName 46 | }; 47 | var validationResults = new List(); 48 | 49 | if (Validator.TryValidateProperty(value, validationContext, validationResults)) return; 50 | 51 | foreach (var validationResult in validationResults) AddError(propertyName, validationResult.ErrorMessage ?? string.Empty); 52 | } 53 | 54 | protected void AddError(string propertyName, string error) 55 | { 56 | if (!_errors.ContainsKey(propertyName)) 57 | _errors[propertyName] = new List(); 58 | 59 | if (_errors[propertyName].Contains(error)) return; 60 | 61 | _errors[propertyName].Add(error); 62 | OnErrorsChanged(propertyName); 63 | } 64 | 65 | protected void ClearErrors(string propertyName) 66 | { 67 | if (_errors.Remove(propertyName)) OnErrorsChanged(propertyName); 68 | } 69 | 70 | protected void ClearAllErrors() 71 | { 72 | var properties = _errors.Keys.ToList(); 73 | _errors.Clear(); 74 | foreach (var property in properties) OnErrorsChanged(property); 75 | } 76 | 77 | private void OnErrorsChanged(string propertyName) 78 | { 79 | ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName)); 80 | } 81 | 82 | protected void ValidateAllProperties() 83 | { 84 | var properties = GetType().GetProperties() 85 | .Where(prop => prop.GetCustomAttributes(typeof(ValidationAttribute), true).Any()); 86 | 87 | foreach (var property in properties) 88 | { 89 | var value = property.GetValue(this); 90 | ValidateProperty(value, property.Name); 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/AboutContent.axaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 19 | 24 | 31 | 36 | 44 | 45 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/AboutContent.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class AboutContent : UserControl 6 | { 7 | public AboutContent() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/AvatarPage.axaml: -------------------------------------------------------------------------------- 1 |  14 | 15 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/AvatarPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class AvatarPage : UserControl 6 | { 7 | public AvatarPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/ButtonsPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class ButtonsPage : UserControl 6 | { 7 | public ButtonsPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/CardsPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class CardsPage : UserControl 6 | { 7 | public CardsPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/CheckBoxesPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class CheckBoxesPage : UserControl 6 | { 7 | public CheckBoxesPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/ComboBoxesPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class ComboBoxesPage : UserControl 6 | { 7 | public ComboBoxesPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/DashboardPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Interactivity; 3 | using LiveChartsCore.Kernel; 4 | using ShadUI.Demo.ViewModels; 5 | using ShadUI.Themes; 6 | 7 | namespace ShadUI.Demo.Views; 8 | 9 | public partial class DashboardPage : UserControl 10 | { 11 | public DashboardPage() 12 | { 13 | InitializeComponent(); 14 | Loaded += OnLoaded; 15 | } 16 | 17 | private void OnLoaded(object? sender, RoutedEventArgs e) 18 | { 19 | if (DataContext is not DashboardViewModel vm) return; 20 | 21 | vm.ThemeWatcher.ThemeChanged += OnThemeChanged; 22 | } 23 | 24 | private void OnThemeChanged(object? sender, ThemeColors e) 25 | { 26 | CartesianChart1.CoreChart.Update(new ChartUpdateParams 27 | { IsAutomaticUpdate = false, Throttling = false }); 28 | CartesianChart2.CoreChart.Update(new ChartUpdateParams 29 | { IsAutomaticUpdate = false, Throttling = false }); 30 | } 31 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/DataGridPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | 5 | namespace ShadUI.Demo.Views; 6 | 7 | public partial class DataGridPage : UserControl 8 | { 9 | public DataGridPage() 10 | { 11 | InitializeComponent(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/DatePage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class DatePage : UserControl 6 | { 7 | public DatePage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/DialogsPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class DialogsPage : UserControl 6 | { 7 | public DialogsPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/InputPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class InputPage : UserControl 6 | { 7 | public InputPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/LoginContent.axaml: -------------------------------------------------------------------------------- 1 |  11 | 15 | 16 | 22 | 28 | 29 | 35 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/LoginContent.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class LoginContent : UserControl 6 | { 7 | public LoginContent() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/MainWindow.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Interactivity; 3 | using ShadUI.Demo.ViewModels; 4 | using Window = ShadUI.Controls.Window; 5 | 6 | namespace ShadUI.Demo.Views; 7 | 8 | public partial class MainWindow : Window 9 | { 10 | public MainWindow() 11 | { 12 | InitializeComponent(); 13 | 14 | Closing += OnClosing; 15 | FullscreenButton.Click += OnFullScreen; 16 | ExitFullscreenButton.Click += OnExitFullScreen; 17 | } 18 | 19 | private void OnFullScreen(object? sender, RoutedEventArgs e) 20 | { 21 | WindowState = WindowState.FullScreen; 22 | } 23 | 24 | private void OnExitFullScreen(object? sender, RoutedEventArgs e) 25 | { 26 | ExitFullScreen(); 27 | } 28 | 29 | private void OnClosing(object? sender, WindowClosingEventArgs e) 30 | { 31 | e.Cancel = true; 32 | 33 | if (DataContext is MainWindowViewModel viewModel) 34 | { 35 | viewModel.TryCloseCommand.Execute(null); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/MenuViewPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class MenuViewPage : UserControl 6 | { 7 | public MenuViewPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/MiscellaneousPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class MiscellaneousPage : UserControl 6 | { 7 | public MiscellaneousPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/PageDataTemplates.axaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/SlidersPage.axaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 33 | 34 | 38 | 39 | 40 | 44 | 45 | 50 | 51 | 52 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/SlidersPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class SlidersPage : UserControl 6 | { 7 | public SlidersPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/SwitchPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class SwitchPage : UserControl 6 | { 7 | public SwitchPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/TabsPage.axaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/TabsPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class TabsPage : UserControl 6 | { 7 | public TabsPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/ThemePage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Markup.Xaml; 4 | 5 | namespace ShadUI.Demo.Views; 6 | 7 | public partial class ThemePage : UserControl 8 | { 9 | public ThemePage() 10 | { 11 | InitializeComponent(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/TimePage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class TimePage : UserControl 6 | { 7 | public TimePage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/ToastsPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class ToastsPage : UserControl 6 | { 7 | public ToastsPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/TogglePage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class TogglePage : UserControl 6 | { 7 | public TogglePage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/ToolTipPage.axaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/ToolTipPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class ToolTipPage : UserControl 6 | { 7 | public ToolTipPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/Views/TypographyPage.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Demo.Views; 4 | 5 | public partial class TypographyPage : UserControl 6 | { 7 | public TypographyPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/ShadUI.Demo/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/ShadUI.Package/Images/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Package/Images/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /src/ShadUI.Package/Images/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Package/Images/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /src/ShadUI.Package/Images/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Package/Images/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /src/ShadUI.Package/Images/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Package/Images/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /src/ShadUI.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /src/ShadUI.Package/Images/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Package/Images/StoreLogo.png -------------------------------------------------------------------------------- /src/ShadUI.Package/Images/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/accntech/shad-ui/c56dfade9f6d90d66dafd22691c6f17b4fad2248/src/ShadUI.Package/Images/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /src/ShadUI.Package/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 9 | 10 | 14 | 15 | 16 | ShadUI App 17 | AccounTech Business Management Services 18 | Images\StoreLogo.png 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/ShadUI/Breakpoints/Breakpoint.cs: -------------------------------------------------------------------------------- 1 | namespace ShadUI.Breakpoints; 2 | 3 | /// 4 | /// Represents the different breakpoints for responsive design. 5 | /// 6 | public enum Breakpoint 7 | { 8 | /// 9 | /// Small breakpoint (up to 640px). 10 | /// 11 | Sm, 12 | 13 | /// 14 | /// Small and up breakpoint (640px and above). 15 | /// 16 | SmAndUp, 17 | 18 | /// 19 | /// Medium and down breakpoint (less than 768px). 20 | /// 21 | MdAndDown, 22 | 23 | /// 24 | /// Medium breakpoint (768px to 1024px). 25 | /// 26 | Md, 27 | 28 | /// 29 | /// Medium and up breakpoint (768px and above). 30 | /// 31 | MdAndUp, 32 | 33 | /// 34 | /// Large and down breakpoint (less than 1024px). 35 | /// 36 | LgAndDown, 37 | 38 | /// 39 | /// Large breakpoint (1024px to 1280px). 40 | /// 41 | Lg, 42 | 43 | /// 44 | /// Large and up breakpoint (1024px and above). 45 | /// 46 | LgAndUp, 47 | 48 | /// 49 | /// Extra large and down breakpoint (less than 1280px). 50 | /// 51 | XlAndDown, 52 | 53 | /// 54 | /// Extra large breakpoint (1280px to 1536px). 55 | /// 56 | Xl, 57 | 58 | /// 59 | /// Extra large and up breakpoint (1280px and above). 60 | /// 61 | XlAndUp, 62 | 63 | /// 64 | /// Extra, extra large breakpoint (1536px and above). 65 | /// 66 | Xxl 67 | } -------------------------------------------------------------------------------- /src/ShadUI/Breakpoints/BreakpointRange.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShadUI.Breakpoints; 5 | 6 | /// 7 | /// Provides a dictionary of breakpoints and their corresponding range functions. 8 | /// 9 | public static class BreakpointRange 10 | { 11 | /// 12 | /// Gets the dictionary of breakpoints and their corresponding range functions. 13 | /// 14 | public static readonly Dictionary> Ranges = 15 | new() 16 | { 17 | { Breakpoint.Sm, width => width <= 640 }, 18 | { Breakpoint.SmAndUp, width => width >= 640 }, 19 | { Breakpoint.MdAndDown, width => width < 768 }, 20 | { Breakpoint.Md, width => width is >= 768 and < 1024 }, 21 | { Breakpoint.MdAndUp, width => width > 768 }, 22 | { Breakpoint.LgAndDown, width => width < 1024 }, 23 | { Breakpoint.Lg, width => width is >= 1024 and < 1280 }, 24 | { Breakpoint.LgAndUp, width => width >= 1024 }, 25 | { Breakpoint.XlAndDown, width => width < 1280 }, 26 | { Breakpoint.Xl, width => width is >= 1280 and < 1536 }, 27 | { Breakpoint.XlAndUp, width => width >= 1280 }, 28 | { Breakpoint.Xxl, width => width >= 1536 } 29 | }; 30 | } -------------------------------------------------------------------------------- /src/ShadUI/Breakpoints/View.axaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/ShadUI/Breakpoints/View.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | 4 | namespace ShadUI.Breakpoints; 5 | 6 | /// 7 | /// Represents a view that can change its layout based on breakpoints. 8 | /// 9 | public class View : Grid 10 | { 11 | /// 12 | /// Defines the property. 13 | /// 14 | public static readonly StyledProperty BreakpointProperty = 15 | AvaloniaProperty.Register(nameof(Breakpoint)); 16 | 17 | /// 18 | /// Gets or sets the breakpoint for the view. 19 | /// 20 | public Breakpoint Breakpoint 21 | { 22 | get => GetValue(BreakpointProperty); 23 | set => SetValue(BreakpointProperty, value); 24 | } 25 | 26 | /// 27 | /// Defines the property. 28 | /// 29 | public static readonly StyledProperty InvertProperty = AvaloniaProperty.Register( 30 | nameof(Invert)); 31 | 32 | /// 33 | /// Gets or sets a value indicating whether to invert the breakpoint logic. 34 | /// 35 | public bool Invert 36 | { 37 | get => GetValue(InvertProperty); 38 | set => SetValue(InvertProperty, value); 39 | } 40 | } -------------------------------------------------------------------------------- /src/ShadUI/Breakpoints/ViewPort.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Breakpoints; 4 | 5 | /// 6 | /// Container for bound content that will only be visible when the specified breakpoint is active. 7 | /// 8 | public class ViewPort : Panel 9 | { 10 | } -------------------------------------------------------------------------------- /src/ShadUI/Controls/Avatar.axaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/ShadUI/Controls/Avatar.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.Primitives; 3 | using Avalonia.Media; 4 | 5 | namespace ShadUI.Controls; 6 | 7 | /// 8 | /// Represents an avatar control that displays an image. 9 | /// 10 | public class Avatar : TemplatedControl 11 | { 12 | /// 13 | /// Defines the property. 14 | /// 15 | public static readonly StyledProperty SourceProperty = 16 | AvaloniaProperty.Register(nameof(Source)); 17 | 18 | /// 19 | /// Gets or sets the source image of the avatar. 20 | /// 21 | public IImage? Source 22 | { 23 | get => GetValue(SourceProperty); 24 | set => SetValue(SourceProperty, value); 25 | } 26 | 27 | /// 28 | /// Defines the property. 29 | /// 30 | public static readonly StyledProperty FallbackProperty = 31 | AvaloniaProperty.Register(nameof(Fallback)); 32 | 33 | /// 34 | /// Gets or sets the fallback text of the avatar. 35 | /// 36 | public string Fallback 37 | { 38 | get => GetValue(FallbackProperty); 39 | set => SetValue(FallbackProperty, value); 40 | } 41 | } -------------------------------------------------------------------------------- /src/ShadUI/Controls/BusyArea.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | 4 | namespace ShadUI.Controls; 5 | 6 | /// 7 | /// Represents a control that displays a busy indicator. 8 | /// 9 | public class BusyArea : ContentControl 10 | { 11 | /// 12 | /// Defines the property. 13 | /// 14 | public static readonly StyledProperty LoadingSizeProperty = 15 | AvaloniaProperty.Register(nameof(LoadingSize)); 16 | 17 | /// 18 | /// Gets or sets the size of the loading indicator. 19 | /// 20 | public double LoadingSize 21 | { 22 | get => GetValue(LoadingSizeProperty); 23 | set => SetValue(LoadingSizeProperty, value); 24 | } 25 | 26 | /// 27 | /// Defines the property. 28 | /// 29 | public static readonly StyledProperty IsBusyProperty = 30 | AvaloniaProperty.Register(nameof(IsBusy)); 31 | 32 | /// 33 | /// Gets or sets a value indicating whether the control is busy. 34 | /// 35 | public bool IsBusy 36 | { 37 | get => GetValue(IsBusyProperty); 38 | set => SetValue(IsBusyProperty, value); 39 | } 40 | } -------------------------------------------------------------------------------- /src/ShadUI/Controls/Calendar.axaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/ShadUI/Controls/Card.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | 4 | namespace ShadUI.Controls; 5 | 6 | /// 7 | /// Represents a card control with header, footer, and shadow properties. 8 | /// 9 | public class Card : ContentControl 10 | { 11 | /// 12 | /// Defines the property. 13 | /// 14 | public static readonly StyledProperty HeaderProperty = 15 | AvaloniaProperty.Register(nameof(Header)); 16 | 17 | /// 18 | /// Gets or sets the header content of the card. 19 | /// 20 | public object? Header 21 | { 22 | get => GetValue(HeaderProperty); 23 | set => SetValue(HeaderProperty, value); 24 | } 25 | 26 | /// 27 | /// Defines the property. 28 | /// 29 | public static readonly StyledProperty FooterProperty = 30 | AvaloniaProperty.Register(nameof(Footer)); 31 | 32 | /// 33 | /// Gets or sets the footer content of the card. 34 | /// 35 | public object? Footer 36 | { 37 | get => GetValue(FooterProperty); 38 | set => SetValue(FooterProperty, value); 39 | } 40 | 41 | /// 42 | /// Defines the property. 43 | /// 44 | public static readonly StyledProperty HasShadowProperty = 45 | AvaloniaProperty.Register(nameof(HasShadow)); 46 | 47 | /// 48 | /// Gets or sets a value indicating whether the card has a shadow. 49 | /// 50 | public bool HasShadow 51 | { 52 | get => GetValue(HasShadowProperty); 53 | set => SetValue(HasShadowProperty, value); 54 | } 55 | } -------------------------------------------------------------------------------- /src/ShadUI/Controls/CardDescription.axaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/ShadUI/Controls/CardDescription.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Controls; 4 | 5 | /// 6 | /// Represents a description control for a card. 7 | /// 8 | public class CardDescription : ContentControl 9 | { 10 | } -------------------------------------------------------------------------------- /src/ShadUI/Controls/CardTitle.axaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/ShadUI/Controls/CardTitle.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | 3 | namespace ShadUI.Controls; 4 | 5 | /// 6 | /// Represents a title control for a card. 7 | /// 8 | public class CardTitle : ContentControl 9 | { 10 | } -------------------------------------------------------------------------------- /src/ShadUI/Controls/Constants.axaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 4 | 6 5 | 8 6 | 12 7 | 16 8 | 24 9 | 32 10 | 999 11 | 0 2 4 0 #20000000 12 | 13 | -------------------------------------------------------------------------------- /src/ShadUI/Controls/DataValidationErrors.axaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 30 | 38 | 39 | 40 | 41 | 42 | 43 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/ShadUI/Controls/Loading.axaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | M10,20c-5.51,0-10-4.49-10-10S4.49,0,10,0c1.05,0,2.09.16,3.09.49.53.17.81.73.64,1.26-.17.53-.73.81-1.26.64-.8-.26-1.63-.39-2.47-.39-4.41,0-8,3.59-8,8s3.59,8,8,8c4.41,0,8-3.59,8-8,0-.55.45-1,1-1s1,.45,1,1c0,5.51-4.49,10-10,10Z 9 | 10 | 11 | 12 | 17 | 18 | 19 | 31 | 32 | -------------------------------------------------------------------------------- /src/ShadUI/Controls/Loading.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls.Primitives; 2 | 3 | namespace ShadUI.Controls; 4 | 5 | /// 6 | /// Represents a loading spinner control. 7 | /// 8 | public class Loading : TemplatedControl 9 | { 10 | } -------------------------------------------------------------------------------- /src/ShadUI/Controls/MenuFlyoutPresenter.axaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 23 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/ShadUI/Controls/SelectableTextBlock.axaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | -------------------------------------------------------------------------------- /src/ShadUI/Controls/Skeleton.axaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 10 | 14 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/ShadUI/Controls/Skeleton.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls.Primitives; 2 | 3 | namespace ShadUI.Controls; 4 | 5 | /// 6 | /// Represents a skeleton loading control. 7 | /// 8 | public sealed class Skeleton : TemplatedControl 9 | { 10 | } -------------------------------------------------------------------------------- /src/ShadUI/Controls/ToolTip.axaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | Text Content 10 | Very long text content which should exceed the maximum with of the tooltip and wrap. 11 | 12 | 13 | Multi-line 14 | Control Content 15 | 16 | 17 | 24 | 25 | 26 | 27 | 28 | 320 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 52 | 58 | 59 | 60 | 61 | 64 | 65 | -------------------------------------------------------------------------------- /src/ShadUI/Converters/BoolToWidthProgressConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | 5 | namespace ShadUI.Converters; 6 | 7 | /// 8 | /// Returns a width of 24 if the value is true, otherwise 0. 9 | /// 10 | internal class BoolToWidthProgressConverter : IValueConverter 11 | { 12 | public static readonly BoolToWidthProgressConverter Instance = new(); 13 | 14 | /// 15 | /// Convert a boolean value to a width of 24 or 0. 16 | /// 17 | /// 18 | /// 19 | /// 20 | /// 21 | /// 22 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 23 | { 24 | if (value == null) 25 | return 0; 26 | 27 | return (bool) value ? 24 : 0; 28 | } 29 | 30 | /// 31 | /// Convert a width of 24 or 0 to a boolean value. 32 | /// 33 | /// 34 | /// 35 | /// 36 | /// 37 | /// 38 | /// 39 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => 40 | throw new NotSupportedException(); 41 | } 42 | 43 | /// 44 | /// Returns a width of 0 if the value is true, otherwise 24. 45 | /// 46 | internal class BoolToInverseWidthProgressConverter : IValueConverter 47 | { 48 | public static readonly BoolToInverseWidthProgressConverter Instance = new(); 49 | 50 | /// 51 | /// Convert a boolean value to a width of 0 or 36. 52 | /// 53 | /// 54 | /// 55 | /// 56 | /// 57 | /// 58 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 59 | { 60 | if (value == null) 61 | return 24; 62 | 63 | return (bool) value ? 0 : 24; 64 | } 65 | 66 | /// 67 | /// Convert a width of 0 or 24 to a boolean value. 68 | /// 69 | /// 70 | /// 71 | /// 72 | /// 73 | /// 74 | /// 75 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => 76 | throw new NotSupportedException(); 77 | } -------------------------------------------------------------------------------- /src/ShadUI/Converters/BooleanConverters.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Data.Converters; 3 | using ShadUI.Controls; 4 | 5 | namespace ShadUI.Converters; 6 | 7 | internal static class BooleanConverters 8 | { 9 | public static readonly IValueConverter ToInverseOpacity = 10 | new FuncValueConverter(value => value ? 0 : 1); 11 | 12 | public static readonly IValueConverter ToLoading = 13 | new FuncValueConverter(value => value ? new Loading() : new Panel()); 14 | } -------------------------------------------------------------------------------- /src/ShadUI/Converters/ClockIdentifierToIsVisibleConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | 5 | namespace ShadUI.Converters; 6 | 7 | internal sealed class ClockIdentifierToIsVisibleConverter : IValueConverter 8 | { 9 | public static ClockIdentifierToIsVisibleConverter Instance { get; } = new(); 10 | 11 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 12 | { 13 | if (value is not string identifier) 14 | throw new ArgumentException("Value must be a string"); 15 | 16 | if (identifier != "12HourClock" && identifier != "24HourClock") 17 | throw new ArgumentException("Value must be either 12HourClock or 24HourClock"); 18 | 19 | return identifier == "12HourClock"; 20 | } 21 | 22 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => 23 | throw new NotImplementedException(); 24 | } -------------------------------------------------------------------------------- /src/ShadUI/Converters/CornerRadiusConverter.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Data.Converters; 3 | 4 | namespace ShadUI.Converters; 5 | 6 | internal static class CornerRadiusConverter 7 | { 8 | public static readonly IValueConverter TopOnly = 9 | new FuncValueConverter(x => new CornerRadius(x.TopLeft, x.TopRight, 0, 0)); 10 | } -------------------------------------------------------------------------------- /src/ShadUI/Converters/DialogButtonStyleToButtonClassConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | using ShadUI.Dialogs; 5 | 6 | namespace ShadUI.Converters; 7 | 8 | internal class DialogButtonStyleToButtonClassConverter : IValueConverter 9 | { 10 | public static readonly DialogButtonStyleToButtonClassConverter Instance = new(); 11 | 12 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 13 | { 14 | if (value is not DialogButtonStyle style) return ""; 15 | 16 | return style switch 17 | { 18 | DialogButtonStyle.Primary => "Primary", 19 | DialogButtonStyle.Secondary => "Secondary", 20 | DialogButtonStyle.Outline => "Outline", 21 | DialogButtonStyle.Ghost => "Ghost", 22 | DialogButtonStyle.Destructive => "Destructive", 23 | _ => "" 24 | }; 25 | } 26 | 27 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => 28 | throw new NotImplementedException(); 29 | } -------------------------------------------------------------------------------- /src/ShadUI/Converters/PopupMaxDropDownHeightConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | 5 | namespace ShadUI.Converters; 6 | 7 | internal class PopupMaxDropDownHeightConverter : IValueConverter 8 | { 9 | public static PopupMaxDropDownHeightConverter Instance => new(); 10 | 11 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => 12 | value is double maxHeight ? maxHeight + 9 : double.NaN; 13 | 14 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => 15 | throw new NotImplementedException(); 16 | } -------------------------------------------------------------------------------- /src/ShadUI/Converters/PopupMinWidthConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia.Data.Converters; 4 | 5 | namespace ShadUI.Converters; 6 | 7 | internal class PopupMinWidthConverter : IValueConverter 8 | { 9 | public static PopupMinWidthConverter Instance => new(); 10 | 11 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => 12 | value is double minWidth ? minWidth + 4 : double.NaN; 13 | 14 | public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => 15 | throw new NotImplementedException(); 16 | } -------------------------------------------------------------------------------- /src/ShadUI/Converters/SideMenuScrollerToVisibilityBool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using Avalonia.Data.Converters; 5 | 6 | namespace ShadUI.Converters; 7 | 8 | /// 9 | /// Converts the value of the sidebar menu scroller to a visibility boolean. 10 | /// 11 | internal class SideMenuScrollerToVisibilityBool : IMultiValueConverter 12 | { 13 | /// 14 | /// Visible up. 15 | /// 16 | public static SideMenuScrollerToVisibilityBool Up { get; } = new((x, y) => x > y); 17 | 18 | /// 19 | /// Visible down. 20 | /// 21 | public static SideMenuScrollerToVisibilityBool Down { get; } = new((x, y) => x < y); 22 | 23 | private readonly Func _converter; 24 | 25 | /// 26 | /// Returns the instance of the . 27 | /// 28 | /// 29 | public SideMenuScrollerToVisibilityBool(Func converter) 30 | { 31 | _converter = converter; 32 | } 33 | 34 | /// 35 | /// Converts the value of the sidebar menu scroller to a visibility boolean. 36 | /// 37 | /// 38 | /// 39 | /// 40 | /// 41 | /// 42 | public object? Convert(IList values, Type targetType, object? parameter, CultureInfo culture) 43 | { 44 | if (values[0] is not double firstVal) return null; 45 | if (values[1] is not double secondVal) return null; 46 | return _converter(firstVal, secondVal); 47 | } 48 | } -------------------------------------------------------------------------------- /src/ShadUI/Converters/SidebarMenuScrollerToOpacityMask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using Avalonia; 5 | using Avalonia.Data.Converters; 6 | using Avalonia.Media; 7 | 8 | namespace ShadUI.Converters; 9 | 10 | /// 11 | /// Converts the value of the sidebar menu scroller to an opacity mask. 12 | /// 13 | internal class SidebarMenuScrollerToOpacityMask : IMultiValueConverter 14 | { 15 | private readonly Func _func; 16 | 17 | /// 18 | /// Top mask. 19 | /// 20 | public static SidebarMenuScrollerToOpacityMask Top { get; } = new((x, y) => x > y ? TopBrush : Brushes.White); 21 | 22 | /// 23 | /// Bottom mask. 24 | /// 25 | public static SidebarMenuScrollerToOpacityMask Bottom { get; } = new((x, y) => x < y ? BottomBrush : Brushes.White); 26 | 27 | private static readonly LinearGradientBrush BottomBrush = new() 28 | { 29 | StartPoint = new RelativePoint(0.5, 0, RelativeUnit.Relative), 30 | EndPoint = new RelativePoint(0.5, 0.95, RelativeUnit.Relative), 31 | GradientStops = 32 | [ 33 | new GradientStop(Colors.Black, 0.9), 34 | new GradientStop(Colors.Transparent, 1) 35 | ] 36 | }; 37 | 38 | private static readonly LinearGradientBrush TopBrush = new() 39 | { 40 | StartPoint = new RelativePoint(0.5, 1, RelativeUnit.Relative), 41 | EndPoint = new RelativePoint(0.5, 0.05, RelativeUnit.Relative), 42 | GradientStops = 43 | [ 44 | new GradientStop(Colors.Black, 0.9), 45 | new GradientStop(Colors.Transparent, 1) 46 | ] 47 | }; 48 | 49 | /// 50 | /// Returns the instance of the . 51 | /// 52 | /// 53 | public SidebarMenuScrollerToOpacityMask(Func func) 54 | { 55 | _func = func; 56 | } 57 | 58 | /// 59 | /// Converts the value of the sidebar menu scroller to an opacity mask. 60 | /// 61 | /// 62 | /// 63 | /// 64 | /// 65 | /// 66 | public object? Convert(IList values, Type targetType, object? parameter, CultureInfo culture) 67 | { 68 | if (values.Count != 2) return null; 69 | if (values[0] is not double valOne) return null; 70 | if (values[1] is not double valTwo) return null; 71 | return _func(valOne, valTwo); 72 | } 73 | } -------------------------------------------------------------------------------- /src/ShadUI/Converters/SidebarMenuScrollerToVisibilityBool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using Avalonia.Data.Converters; 5 | 6 | namespace ShadUI.Converters; 7 | 8 | /// 9 | /// Converts the value of the sidebar menu scroller to a visibility boolean. 10 | /// 11 | internal class SidebarMenuScrollerToVisibilityBool : IMultiValueConverter 12 | { 13 | /// 14 | /// Returns the up instance of the . 15 | /// 16 | public static SidebarMenuScrollerToVisibilityBool Up { get; } = new((x, y) => x > y); 17 | 18 | /// 19 | /// Returns the down instance of the . 20 | /// 21 | public static SidebarMenuScrollerToVisibilityBool Down { get; } = new((x, y) => x < y); 22 | 23 | private readonly Func _converter; 24 | 25 | /// 26 | /// Returns the instance of the . 27 | /// 28 | /// 29 | public SidebarMenuScrollerToVisibilityBool(Func converter) 30 | { 31 | _converter = converter; 32 | } 33 | 34 | /// 35 | /// Converts the value of the sidebar menu scroller to a visibility boolean. 36 | /// 37 | /// 38 | /// 39 | /// 40 | /// 41 | /// 42 | public object? Convert(IList values, Type targetType, object? parameter, CultureInfo culture) 43 | { 44 | if (values[0] is not double firstVal) return null; 45 | if (values[1] is not double secondVal) return null; 46 | return _converter(firstVal, secondVal); 47 | } 48 | } -------------------------------------------------------------------------------- /src/ShadUI/Converters/WidthToVisibilityConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using Avalonia.Data.Converters; 5 | using ShadUI.Breakpoints; 6 | 7 | namespace ShadUI.Converters; 8 | 9 | /// 10 | /// Converts the width and breakpoint to a visibility value. 11 | /// 12 | public class WidthToVisibilityConverter : IMultiValueConverter 13 | { 14 | /// 15 | /// Gets the singleton instance of the . 16 | /// 17 | public static WidthToVisibilityConverter Instance => new(); 18 | 19 | /// 20 | /// Converts the width and breakpoint to a visibility value. 21 | /// 22 | /// The values to convert. Expects width, breakpoint, and invert flag. 23 | /// The type of the binding target property. 24 | /// The converter parameter to use. 25 | /// The culture to use in the converter. 26 | /// A boolean value indicating visibility. 27 | public object? Convert(IList values, Type targetType, object? parameter, CultureInfo culture) 28 | { 29 | if (values[0] is not double width) return true; 30 | if (values[1] is not Breakpoint breakpoint) return true; 31 | if (values[2] is not bool invert) return true; 32 | var isVisible = BreakpointRange.Ranges.TryGetValue(breakpoint, out var condition) && 33 | condition(width); 34 | return invert ? !isVisible : isVisible; 35 | } 36 | } -------------------------------------------------------------------------------- /src/ShadUI/Converters/WindowBackgroundToCornerRadiusConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia; 4 | using Avalonia.Data.Converters; 5 | 6 | namespace ShadUI.Converters; 7 | 8 | /// 9 | /// Converts the value of the window background to a corner radius. 10 | /// 11 | internal class WindowBackgroundToCornerRadiusConverter : IValueConverter 12 | { 13 | /// 14 | /// Returns the instance of the . 15 | /// 16 | public static readonly WindowBackgroundToCornerRadiusConverter Instance = new(); 17 | 18 | /// 19 | /// Converts the value of the window background to a corner radius. 20 | /// 21 | /// 22 | /// 23 | /// 24 | /// 25 | /// 26 | public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 27 | { 28 | if (value == null) 29 | return new CornerRadius(0); 30 | 31 | if ((bool) value == false) 32 | return new CornerRadius(17); 33 | 34 | return new CornerRadius(0); 35 | } 36 | 37 | /// 38 | /// Converts the value of corner radius to the window background. 39 | /// 40 | /// 41 | /// 42 | /// 43 | /// 44 | /// 45 | /// 46 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => 47 | throw new NotSupportedException(); 48 | } -------------------------------------------------------------------------------- /src/ShadUI/Converters/WindowBackgroundToMarginConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using Avalonia; 4 | using Avalonia.Data.Converters; 5 | 6 | namespace ShadUI.Converters; 7 | 8 | /// 9 | /// Converts the value of the window background to a margin. 10 | /// 11 | internal class WindowBackgroundToMarginConverter : IValueConverter 12 | { 13 | /// 14 | /// Returns the instance of the . 15 | /// 16 | public static readonly WindowBackgroundToMarginConverter Instance = new(); 17 | 18 | /// 19 | /// Converts the value of the window background to a margin. 20 | /// 21 | /// 22 | /// 23 | /// 24 | /// 25 | /// 26 | public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) 27 | { 28 | if (value == null) 29 | return new Thickness(0); 30 | 31 | if ((bool) value == false) 32 | return new Thickness(10, 5, 0, 10); 33 | 34 | return new Thickness(0); 35 | } 36 | 37 | /// 38 | /// Converts the value of margin to the window background. 39 | /// 40 | /// 41 | /// 42 | /// 43 | /// 44 | /// 45 | /// 46 | public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => 47 | throw new NotSupportedException(); 48 | } -------------------------------------------------------------------------------- /src/ShadUI/Dialogs/CloseDialogOptions.cs: -------------------------------------------------------------------------------- 1 | namespace ShadUI.Dialogs; 2 | 3 | /// 4 | /// Options for closing a dialog. 5 | /// 6 | public sealed class CloseDialogOptions 7 | { 8 | /// 9 | /// Indicates whether the dialog was closed successfully. 10 | /// 11 | public bool Success { get; set; } 12 | 13 | /// 14 | /// Specifies whether all dialogs should be cleared when closing this dialog. 15 | /// 16 | public bool ClearAll { get; set; } 17 | } -------------------------------------------------------------------------------- /src/ShadUI/Dialogs/DialogBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Avalonia.Controls; 4 | 5 | namespace ShadUI.Dialogs; 6 | 7 | /// 8 | /// Builds a dialog. 9 | /// 10 | /// The DataContext of a control 11 | public sealed class DialogBuilder 12 | { 13 | private readonly DialogManager _manager; 14 | 15 | internal DialogBuilder(DialogManager manager) 16 | { 17 | _manager = manager; 18 | } 19 | 20 | internal Action? OnCancelCallback { get; set; } 21 | internal Func? OnCancelAsyncCallback { get; set; } 22 | internal Action? OnSuccessCallback { get; set; } 23 | internal Func? OnSuccessAsyncCallback { get; set; } 24 | internal DialogOptions Options { get; } = new(); 25 | 26 | private Control? _control; 27 | 28 | internal DialogBuilder CreateDialog(TContext context) 29 | { 30 | if (!_manager.CustomDialogs.TryGetValue(typeof(TContext), out var type)) 31 | throw new InvalidOperationException($"Custom dialog with {typeof(TContext)} is not registered."); 32 | 33 | _control = Activator.CreateInstance(type) as Control; 34 | 35 | if (_control == null) throw new InvalidOperationException("Dialog control is not set."); 36 | 37 | _control.DataContext = context; 38 | return this; 39 | } 40 | 41 | internal void Show() 42 | { 43 | if (_control == null) throw new InvalidOperationException("Dialog control is not set."); 44 | 45 | if (OnSuccessCallback != null) 46 | _manager.OnSuccessCallbacks.TryAdd(typeof(TContext), OnSuccessCallback); 47 | 48 | if (OnSuccessAsyncCallback != null) 49 | _manager.OnSuccessAsyncCallbacks.TryAdd(typeof(TContext), OnSuccessAsyncCallback); 50 | 51 | if (OnCancelCallback != null) 52 | _manager.OnCancelCallbacks.TryAdd(typeof(TContext), OnCancelCallback); 53 | 54 | if (OnCancelAsyncCallback != null) 55 | _manager.OnCancelAsyncCallbacks.TryAdd(typeof(TContext), OnCancelAsyncCallback); 56 | 57 | _manager.Show(_control, Options); 58 | } 59 | } -------------------------------------------------------------------------------- /src/ShadUI/Dialogs/DialogButtonStyle.cs: -------------------------------------------------------------------------------- 1 | namespace ShadUI.Dialogs; 2 | 3 | /// 4 | /// Defines the style of the button in the simple dialog. 5 | /// 6 | public enum DialogButtonStyle 7 | { 8 | /// 9 | /// Sets the button style class as Primary. 10 | /// 11 | Primary, 12 | 13 | /// 14 | /// Sets the button style class as Secondary. 15 | /// 16 | Secondary, 17 | 18 | /// 19 | /// Sets the button style class as Outline. 20 | /// 21 | Outline, 22 | 23 | /// 24 | /// Sets the button style class as Ghost. 25 | /// 26 | Ghost, 27 | 28 | /// 29 | /// Sets the button style class as Destruct 30 | /// 31 | Destructive 32 | } -------------------------------------------------------------------------------- /src/ShadUI/Dialogs/DialogOptions.cs: -------------------------------------------------------------------------------- 1 | namespace ShadUI.Dialogs; 2 | 3 | /// 4 | /// Dialog options used to configure the dialog. 5 | /// 6 | public class DialogOptions 7 | { 8 | /// 9 | /// Determines whether the dialog can be dismissed other than clicking/tapping an action button. 10 | /// 11 | public bool Dismissible { get; set; } 12 | 13 | /// 14 | /// Determines the maximum width of the dialog. 15 | /// 16 | public double MaxWidth { get; set; } 17 | 18 | /// 19 | /// Determines the minimum width of the dialog. 20 | /// 21 | public double MinWidth { get; set; } 22 | } -------------------------------------------------------------------------------- /src/ShadUI/Dialogs/SimpleDialogBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace ShadUI.Dialogs; 5 | 6 | /// 7 | /// Builds a simple dialog. 8 | /// 9 | public sealed class SimpleDialogBuilder 10 | { 11 | private readonly DialogManager _manager; 12 | private SimpleDialog? _dialog; 13 | 14 | internal SimpleDialogBuilder(DialogManager manager) 15 | { 16 | _manager = manager; 17 | } 18 | 19 | internal string PrimaryButtonText { get; set; } = string.Empty; 20 | internal Action? PrimaryCallback { get; set; } 21 | internal Func? PrimaryCallbackAsync { get; set; } 22 | internal DialogButtonStyle PrimaryButtonStyle { get; set; } = DialogButtonStyle.Primary; 23 | internal string SecondaryButtonText { get; set; } = string.Empty; 24 | internal Action? SecondaryCallback { get; set; } 25 | internal Func? SecondaryCallbackAsync { get; set; } 26 | internal DialogButtonStyle SecondaryButtonStyle { get; set; } = DialogButtonStyle.Secondary; 27 | internal string TertiaryButtonText { get; set; } = string.Empty; 28 | internal Action? TertiaryCallback { get; set; } 29 | internal Func? TertiaryCallbackAsync { get; set; } 30 | internal DialogButtonStyle TertiaryButtonStyle { get; set; } = DialogButtonStyle.Outline; 31 | internal string CancelButtonText { get; set; } = "Cancel"; 32 | internal Action? CancelCallback { get; set; } 33 | internal Func? CancelCallbackAsync { get; set; } 34 | internal DialogButtonStyle CancelButtonStyle { get; set; } = DialogButtonStyle.Outline; 35 | internal DialogOptions Options { get; } = new(); 36 | 37 | internal SimpleDialogBuilder CreateDialog(string title, string message) 38 | { 39 | _dialog = new SimpleDialog(_manager) 40 | { 41 | Title = title, 42 | Message = message 43 | }; 44 | return this; 45 | } 46 | 47 | internal void Show() 48 | { 49 | _dialog ??= new SimpleDialog(_manager); 50 | 51 | _dialog.PrimaryButtonText = PrimaryButtonText; 52 | _dialog.PrimaryCallback = PrimaryCallback; 53 | _dialog.PrimaryCallbackAsync = PrimaryCallbackAsync; 54 | _dialog.PrimaryButtonStyle = PrimaryButtonStyle; 55 | _dialog.SecondaryButtonText = SecondaryButtonText; 56 | _dialog.SecondaryCallback = SecondaryCallback; 57 | _dialog.SecondaryCallbackAsync = SecondaryCallbackAsync; 58 | _dialog.SecondaryButtonStyle = SecondaryButtonStyle; 59 | _dialog.TertiaryButtonText = TertiaryButtonText; 60 | _dialog.TertiaryCallback = TertiaryCallback; 61 | _dialog.TertiaryCallbackAsync = TertiaryCallbackAsync; 62 | _dialog.TertiaryButtonStyle = TertiaryButtonStyle; 63 | _dialog.CancelButtonText = CancelButtonText; 64 | _dialog.CancelCallback = CancelCallback; 65 | _dialog.CancelCallbackAsync = CancelCallbackAsync; 66 | _dialog.CancelButtonStyle = CancelButtonStyle; 67 | 68 | _dialog.SetId(Options); 69 | _manager.Show(_dialog, Options); 70 | } 71 | } -------------------------------------------------------------------------------- /src/ShadUI/Enums/LoadingStyle.cs: -------------------------------------------------------------------------------- 1 | namespace ShadUI.Enums; 2 | 3 | /// 4 | /// Styles for the loading indicator. 5 | /// 6 | public enum LoadingStyle 7 | { 8 | /// 9 | /// A simple loading indicator. 10 | /// 11 | Simple, 12 | 13 | /// 14 | /// A glowing loading indicator. 15 | /// 16 | Glow, 17 | 18 | /// 19 | /// A loading indicator with pellets. 20 | /// 21 | Pellets 22 | } -------------------------------------------------------------------------------- /src/ShadUI/Extensions/Application.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Controls; 2 | using Avalonia.Controls.ApplicationLifetimes; 3 | using Avalonia.VisualTree; 4 | 5 | namespace ShadUI.Extensions; 6 | 7 | /// 8 | /// Provides extension methods for class. 9 | /// 10 | internal static class Application 11 | { 12 | /// 13 | /// Gets the top-level window or visual element from an . 14 | /// 15 | /// The instance. 16 | /// 17 | /// The top-level window or visual element if found; otherwise, null. 18 | /// For desktop applications, returns the main window. 19 | /// For single-view applications, returns the visual root of the main view. 20 | /// 21 | public static TopLevel? GetTopLevel(this Avalonia.Application? app) 22 | { 23 | if (app is null) return null; 24 | 25 | if (app.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) return desktop.MainWindow; 26 | if (app.ApplicationLifetime is ISingleViewApplicationLifetime viewApp) 27 | { 28 | var visualRoot = viewApp.MainView?.GetVisualRoot(); 29 | return visualRoot as TopLevel; 30 | } 31 | return null; 32 | } 33 | } -------------------------------------------------------------------------------- /src/ShadUI/Extensions/ButtonAssist.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Media; 4 | 5 | namespace ShadUI.Extensions; 6 | 7 | /// 8 | /// Useful extensions for the class. 9 | /// 10 | public static class ButtonAssist 11 | { 12 | /// 13 | /// Show or hide the progress indicator. 14 | /// 15 | public static readonly AttachedProperty ShowProgressProperty = 16 | AvaloniaProperty.RegisterAttached("ShowProgress", typeof(Button)); 17 | 18 | /// 19 | /// Get the value of the . 20 | /// 21 | /// 22 | /// 23 | public static bool GetShowProgress(Button textBox) => textBox.GetValue(ShowProgressProperty); 24 | 25 | /// 26 | /// Set the value of the . 27 | /// 28 | /// 29 | /// 30 | public static void SetShowProgress(Button textBox, bool value) 31 | { 32 | textBox.SetValue(ShowProgressProperty, value); 33 | } 34 | 35 | /// 36 | /// Add button icon. 37 | /// 38 | public static readonly AttachedProperty IconProperty = 39 | AvaloniaProperty.RegisterAttached("Icon", typeof(Button)); 40 | 41 | /// 42 | /// Get the value of the . 43 | /// 44 | /// 45 | /// 46 | public static object GetIcon(Button textBox) => textBox.GetValue(IconProperty); 47 | 48 | /// 49 | /// Set the value of the . 50 | /// 51 | /// 52 | /// 53 | public static void SetIcon(Button textBox, object value) 54 | { 55 | textBox.SetValue(IconProperty, value); 56 | } 57 | 58 | /// 59 | /// Attached property for setting the hover background brush of a . 60 | /// 61 | public static readonly AttachedProperty HoverBackgroundProperty = 62 | AvaloniaProperty.RegisterAttached("HoverBackground", typeof(Button)); 63 | 64 | /// 65 | /// Sets the hover background brush for the specified . 66 | /// 67 | /// The button to set the hover background for. 68 | /// The brush to use as the hover background. 69 | public static void SetHoverBackground(Button btn, IBrush value) => btn.SetValue(HoverBackgroundProperty, value); 70 | 71 | /// 72 | /// Gets the hover background brush for the specified . 73 | /// 74 | /// The button to get the hover background from. 75 | /// The brush used as the hover background. 76 | public static IBrush GetHoverBackground(Button btn) => btn.GetValue(HoverBackgroundProperty); 77 | } -------------------------------------------------------------------------------- /src/ShadUI/Extensions/ElementAssist.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Data; 4 | 5 | namespace ShadUI.Extensions; 6 | 7 | /// 8 | /// Useful extensions for any element. 9 | /// 10 | public class ElementAssist 11 | { 12 | static ElementAssist() 13 | { 14 | ClassesProperty.Changed.AddClassHandler(HandleClassesChanged); 15 | FocusOnLoadProperty.Changed.AddClassHandler(HandleFocusOnLoadChanged); 16 | } 17 | 18 | /// 19 | /// Set the classes of the element using . 20 | /// 21 | public static readonly AttachedProperty ClassesProperty = 22 | AvaloniaProperty.RegisterAttached( 23 | "Classes", "", false, BindingMode.OneTime); 24 | 25 | private static void HandleClassesChanged(AvaloniaObject element, AvaloniaPropertyChangedEventArgs args) 26 | { 27 | if (element is not StyledElement styled) return; 28 | 29 | var classes = args.NewValue as string; 30 | 31 | styled.Classes.Clear(); 32 | styled.Classes.AddRange(Classes.Parse(classes ?? "")); 33 | } 34 | 35 | /// 36 | /// Sets the classes of the element. 37 | /// 38 | /// 39 | /// 40 | public static void SetClasses(AvaloniaObject element, string value) 41 | { 42 | element.SetValue(ClassesProperty, value); 43 | } 44 | 45 | /// 46 | /// Gets the classes of the element. 47 | /// 48 | /// 49 | /// 50 | public static string GetClasses(AvaloniaObject element) => element.GetValue(ClassesProperty); 51 | 52 | /// 53 | /// Gets whether the element should be focused when loaded. 54 | /// 55 | public static readonly AttachedProperty FocusOnLoadProperty = 56 | AvaloniaProperty.RegisterAttached( 57 | "FocusOnLoad", false, false, BindingMode.OneTime); 58 | 59 | /// 60 | /// Sets whether the element should be focused when loaded. 61 | /// 62 | public static void SetFocusOnLoad(AvaloniaObject element, bool value) 63 | { 64 | element.SetValue(FocusOnLoadProperty, value); 65 | } 66 | 67 | /// 68 | /// Gets whether the element should be focused when loaded. 69 | /// 70 | public static bool GetFocusOnLoad(AvaloniaObject element) 71 | => element.GetValue(FocusOnLoadProperty); 72 | 73 | private static void HandleFocusOnLoadChanged(AvaloniaObject element, AvaloniaPropertyChangedEventArgs args) 74 | { 75 | if (element is not Control control) return; 76 | 77 | control.Loaded += (_, _) => 78 | { 79 | if (!GetFocusOnLoad(control)) return; 80 | 81 | control.Focus(); 82 | if (control is TextBox textBox) textBox.CaretIndex = textBox.Text?.Length ?? 0; 83 | }; 84 | } 85 | } -------------------------------------------------------------------------------- /src/ShadUI/Extensions/ItemsControlAssist.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Rendering.Composition; 4 | 5 | namespace ShadUI.Extensions; 6 | 7 | /// 8 | /// Useful extension methods for 9 | /// 10 | public static class ItemsControlAssist 11 | { 12 | /// 13 | /// Gets or sets if scroll is animated. 14 | /// 15 | public static readonly AttachedProperty AnimatedScrollProperty = 16 | AvaloniaProperty.RegisterAttached("AnimatedScroll", 17 | typeof(ItemsControl)); 18 | 19 | static ItemsControlAssist() 20 | { 21 | AnimatedScrollProperty.Changed.AddClassHandler(HandleAnimatedScrollChanged); 22 | } 23 | 24 | private static void HandleAnimatedScrollChanged(ItemsControl interactElem, 25 | AvaloniaPropertyChangedEventArgs args) 26 | { 27 | if (GetAnimatedScroll(interactElem)) 28 | interactElem.AttachedToVisualTree += (_, _) => 29 | Scrollable.MakeScrollable(ElementComposition.GetElementVisual(interactElem)); 30 | } 31 | 32 | /// 33 | /// Gets the value of 34 | /// 35 | /// 36 | /// 37 | public static bool GetAnimatedScroll(ItemsControl wrap) => wrap.GetValue(AnimatedScrollProperty); 38 | 39 | /// 40 | /// Sets the value of 41 | /// 42 | /// 43 | /// 44 | public static void SetAnimatedScroll(ItemsControl wrap, bool value) 45 | { 46 | wrap.SetValue(AnimatedScrollProperty, value); 47 | } 48 | } -------------------------------------------------------------------------------- /src/ShadUI/Extensions/ItemsPresenterAssist.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls.Presenters; 3 | using Avalonia.Rendering.Composition; 4 | 5 | namespace ShadUI.Extensions; 6 | 7 | /// 8 | /// Useful extension methods for . 9 | /// 10 | public static class ItemsPresenterAssist 11 | { 12 | /// 13 | /// Gets or sets if scroll is animated. 14 | /// 15 | public static readonly AttachedProperty AnimatedScrollProperty = 16 | AvaloniaProperty.RegisterAttached("AnimatedScroll", 17 | typeof(ItemsPresenter)); 18 | 19 | static ItemsPresenterAssist() 20 | { 21 | AnimatedScrollProperty.Changed.AddClassHandler(HandleAnimatedScrollChanged); 22 | } 23 | 24 | private static void HandleAnimatedScrollChanged(ItemsPresenter interactElem, 25 | AvaloniaPropertyChangedEventArgs args) 26 | { 27 | if (GetAnimatedScroll(interactElem)) 28 | interactElem.AttachedToVisualTree += (_, _) => 29 | Scrollable.MakeScrollable(ElementComposition.GetElementVisual(interactElem)); 30 | } 31 | 32 | /// 33 | /// Gets the value of 34 | /// 35 | /// 36 | /// 37 | public static bool GetAnimatedScroll(ItemsPresenter wrap) => wrap.GetValue(AnimatedScrollProperty); 38 | 39 | /// 40 | /// Sets the value of 41 | /// 42 | /// 43 | /// 44 | public static void SetAnimatedScroll(ItemsPresenter wrap, bool value) 45 | { 46 | wrap.SetValue(AnimatedScrollProperty, value); 47 | } 48 | } -------------------------------------------------------------------------------- /src/ShadUI/Extensions/Scrollable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia.Rendering.Composition; 3 | 4 | namespace ShadUI.Extensions; 5 | 6 | /// 7 | /// Usable extension methods for making an element scrollable. 8 | /// 9 | internal static class Scrollable 10 | { 11 | /// 12 | /// Makes the visual scrollable. 13 | /// 14 | /// 15 | public static void MakeScrollable(CompositionVisual? compositionVisual) 16 | { 17 | if (compositionVisual == null) 18 | return; 19 | 20 | var compositor = compositionVisual.Compositor; 21 | 22 | var animationGroup = compositor.CreateAnimationGroup(); 23 | var offsetAnimation = compositor.CreateVector3KeyFrameAnimation(); 24 | offsetAnimation.Target = "Offset"; 25 | 26 | offsetAnimation.InsertExpressionKeyFrame(1.0f, "this.FinalValue"); 27 | offsetAnimation.Duration = TimeSpan.FromMilliseconds(250); 28 | 29 | var implicitAnimationCollection = compositor.CreateImplicitAnimationCollection(); 30 | animationGroup.Add(offsetAnimation); 31 | implicitAnimationCollection["Offset"] = animationGroup; 32 | compositionVisual.ImplicitAnimations = implicitAnimationCollection; 33 | } 34 | } -------------------------------------------------------------------------------- /src/ShadUI/Extensions/StackPanelAssist.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | using Avalonia.Rendering.Composition; 4 | 5 | namespace ShadUI.Extensions; 6 | 7 | /// 8 | /// Useful extension methods for 9 | /// 10 | public static class StackPanelAssist 11 | { 12 | /// 13 | /// Gets or sets if scroll is animated. 14 | /// 15 | public static readonly AttachedProperty AnimatedScrollProperty = 16 | AvaloniaProperty.RegisterAttached("AnimatedScroll", 17 | typeof(StackPanel)); 18 | 19 | static StackPanelAssist() 20 | { 21 | AnimatedScrollProperty.Changed.AddClassHandler(HandleAnimatedScrollChanged); 22 | } 23 | 24 | private static void HandleAnimatedScrollChanged(StackPanel interactElem, 25 | AvaloniaPropertyChangedEventArgs args) 26 | { 27 | if (GetAnimatedScroll(interactElem)) 28 | interactElem.AttachedToVisualTree += (_, _) => 29 | Scrollable.MakeScrollable(ElementComposition.GetElementVisual(interactElem)); 30 | } 31 | 32 | /// 33 | /// Gets the value of 34 | /// 35 | /// 36 | /// 37 | public static bool GetAnimatedScroll(StackPanel wrap) => wrap.GetValue(AnimatedScrollProperty); 38 | 39 | /// 40 | /// Sets the value of 41 | /// 42 | /// 43 | /// 44 | public static void SetAnimatedScroll(StackPanel wrap, bool value) 45 | { 46 | wrap.SetValue(AnimatedScrollProperty, value); 47 | } 48 | } -------------------------------------------------------------------------------- /src/ShadUI/Extensions/ToggleSwitchAssist.cs: -------------------------------------------------------------------------------- 1 | using Avalonia; 2 | using Avalonia.Controls; 3 | 4 | namespace ShadUI.Extensions; 5 | 6 | /// 7 | /// Useful extensions for the class. 8 | /// 9 | public static class ToggleSwitchAssist 10 | { 11 | /// 12 | /// Determines whether the toggle switch on/of content is right-aligned. 13 | /// 14 | public static readonly AttachedProperty RightAlignedContentProperty = 15 | AvaloniaProperty.RegisterAttached("RightAlignedContent", 16 | typeof(ToggleSwitch)); 17 | 18 | /// 19 | /// Gets the value of the . 20 | /// 21 | /// 22 | /// 23 | public static bool GetRightAlignedContent(ToggleSwitch toggleSwitch) => 24 | toggleSwitch.GetValue(RightAlignedContentProperty); 25 | 26 | /// 27 | /// Sets the value of the . 28 | /// 29 | /// 30 | /// 31 | public static void SetRightAlignedContent(ToggleSwitch toggleSwitch, bool value) 32 | { 33 | toggleSwitch.SetValue(RightAlignedContentProperty, value); 34 | } 35 | } -------------------------------------------------------------------------------- /src/ShadUI/ShadUI.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.1 4 | True 5 | 0.0.1 6 | 0.0.1 7 | 0.0.1 8 | enable 9 | latest 10 | AnyCPU;x64 11 | 12 | 13 | 14 | true 15 | true 16 | README.md 17 | Avalonia-based Desktop UI Library inspired by shadcn and Suki UI Library 18 | avalonia;avaloniaui;ui;theme;shadui 19 | https://github.com/accntech/shad-ui.git 20 | https://github.com/accntech/shad-ui.git 21 | icon.png 22 | accntech 23 | 24 | 25 | 26 | 27 | 28 | 29 | all 30 | runtime; build; native; contentfiles; analyzers; buildtransitive 31 | 32 | 33 | 34 | 35 | 36 | 37 | preview 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/ShadUI/Styles/DataGrid.axaml: -------------------------------------------------------------------------------- 1 |  5 | 9 | 12 | 13 | 16 | 19 | 22 | 25 | 28 | 31 | 34 | -------------------------------------------------------------------------------- /src/ShadUI/Styles/Index.axaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/ShadUI/Styles/Loading.axaml: -------------------------------------------------------------------------------- 1 |  5 | 8 | 11 | 12 | 15 | 16 | 19 | 20 | 23 | 24 | 27 | 28 | 31 | 32 | 35 | 36 | 39 | -------------------------------------------------------------------------------- /src/ShadUI/Styles/SelectableTextBlock.axaml: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 12 | 13 | 18 | 19 | 24 | 25 | 29 | 30 | 35 | 36 | 41 | 42 | 46 | 47 | 51 | 52 | 55 | 56 | 59 | -------------------------------------------------------------------------------- /src/ShadUI/Styles/Separator.axaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 7 | -------------------------------------------------------------------------------- /src/ShadUI/Styles/TextBlock.axaml: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 12 | 13 | 18 | 19 | 24 | 25 | 29 | 30 | 35 | 36 | 41 | 42 | 46 | 47 | 51 | 52 | 55 | 56 | 59 | -------------------------------------------------------------------------------- /src/ShadUI/Themes/ShadTheme.axaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/ShadUI/Themes/ShadTheme.axaml.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Markup.Xaml; 2 | using Avalonia.Styling; 3 | 4 | namespace ShadUI.Themes; 5 | 6 | /// 7 | /// The main theme for the application. 8 | /// 9 | public class ShadTheme : Styles 10 | { 11 | /// 12 | /// Returns a new instance of the class. 13 | /// 14 | public ShadTheme() 15 | { 16 | AvaloniaXamlLoader.Load(this); 17 | } 18 | } -------------------------------------------------------------------------------- /src/ShadUI/Themes/ThemeColors.cs: -------------------------------------------------------------------------------- 1 | using Avalonia.Media; 2 | 3 | namespace ShadUI.Themes; 4 | 5 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 6 | public class ThemeColors 7 | { 8 | // Basic Colors 9 | public Color ForegroundColor { get; set; } 10 | public Color ForegroundLeadColor { get; set; } 11 | public Color BackgroundColor { get; set; } 12 | public Color MutedColor { get; set; } 13 | public Color BorderColor { get; set; } 14 | public Color BorderColor60 { get; set; } 15 | public Color BorderColor30 { get; set; } 16 | public Color OutlineColor { get; set; } 17 | public Color GhostColor { get; set; } 18 | public Color GhostHoverColor { get; set; } 19 | public Color GhostHoverColor50 { get; set; } 20 | 21 | // Theme Colors 22 | public Color PrimaryColor { get; set; } 23 | public Color PrimaryColor75 { get; set; } 24 | public Color PrimaryColor50 { get; set; } 25 | public Color PrimaryColor10 { get; set; } 26 | public Color PrimaryForegroundColor { get; set; } 27 | public Color SecondaryColor { get; set; } 28 | public Color SecondaryColor75 { get; set; } 29 | public Color SecondaryColor50 { get; set; } 30 | public Color SecondaryForegroundColor { get; set; } 31 | public Color DestructiveColor { get; set; } 32 | public Color DestructiveColor75 { get; set; } 33 | public Color DestructiveColor50 { get; set; } 34 | public Color DestructiveColor10 { get; set; } 35 | public Color DestructiveForegroundColor { get; set; } 36 | 37 | // Notification Colors 38 | public Color InfoColor { get; set; } 39 | public Color InfoColor60 { get; set; } 40 | public Color InfoColor20 { get; set; } 41 | public Color InfoColor10 { get; set; } 42 | public Color InfoColor5 { get; set; } 43 | public Color SuccessColor { get; set; } 44 | public Color SuccessColor60 { get; set; } 45 | public Color SuccessColor20 { get; set; } 46 | public Color SuccessColor10 { get; set; } 47 | public Color SuccessColor5 { get; set; } 48 | public Color WarningColor { get; set; } 49 | public Color WarningColor60 { get; set; } 50 | public Color WarningColor20 { get; set; } 51 | public Color WarningColor10 { get; set; } 52 | public Color WarningColor5 { get; set; } 53 | public Color ErrorColor { get; set; } 54 | public Color ErrorColor60 { get; set; } 55 | public Color ErrorColor20 { get; set; } 56 | public Color ErrorColor10 { get; set; } 57 | public Color ErrorColor5 { get; set; } 58 | 59 | // Specific Control Colors 60 | public Color BusyAreaOverlayColor { get; set; } 61 | public Color CardBackgroundColor { get; set; } 62 | public Color DialogOverlayColor { get; set; } 63 | public Color DialogBackgroundColor { get; set; } 64 | public Color TitleBarBackgroundColor { get; set; } 65 | public Color WindowBackgroundColor { get; set; } 66 | public Color WindowButtonHoverColor { get; set; } 67 | public Color SidebarBackgroundColor { get; set; } 68 | public Color SwitchBackgroundColor { get; set; } 69 | public Color SwitchForegroundColor { get; set; } 70 | public Color TabItemSelectedColor { get; set; } 71 | public Color TabItemsBackgroundColor { get; set; } 72 | } 73 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member -------------------------------------------------------------------------------- /src/ShadUI/Themes/ThemeMode.cs: -------------------------------------------------------------------------------- 1 | namespace ShadUI.Themes; 2 | 3 | /// 4 | /// Represents the different theme modes available in the application. 5 | /// 6 | public enum ThemeMode 7 | { 8 | /// 9 | /// The theme base on the system. 10 | /// 11 | System, 12 | 13 | /// 14 | /// The light theme. 15 | /// 16 | Light, 17 | 18 | /// 19 | /// The dark theme. 20 | /// 21 | Dark 22 | } -------------------------------------------------------------------------------- /src/ShadUI/Toasts/Notification.cs: -------------------------------------------------------------------------------- 1 | namespace ShadUI.Toasts; 2 | 3 | /// 4 | /// Defines the type of notification. 5 | /// 6 | public enum Notification 7 | { 8 | /// 9 | /// Basic notification. 10 | /// 11 | Basic, 12 | 13 | /// 14 | /// Info styled notification. 15 | /// 16 | Info, 17 | 18 | /// 19 | /// Success styled notification. 20 | /// 21 | Success, 22 | 23 | /// 24 | /// Warning styled notification. 25 | /// 26 | Warning, 27 | 28 | /// 29 | /// Error styled notification. 30 | /// 31 | Error 32 | } -------------------------------------------------------------------------------- /src/ShadUI/Toasts/ToastBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ShadUI.Toasts; 4 | 5 | /// 6 | /// Builds a toast notification. 7 | /// 8 | public sealed class ToastBuilder 9 | { 10 | private readonly ToastManager _manager; 11 | 12 | /// 13 | /// Returns a new instance of . 14 | /// 15 | /// The toast manager 16 | internal ToastBuilder(ToastManager manager) 17 | { 18 | _manager = manager; 19 | } 20 | 21 | private Toast? _toast; 22 | 23 | internal Notification Notification { get; set; } 24 | 25 | internal object? Content { get; set; } 26 | 27 | internal double Delay { get; set; } = 10; 28 | 29 | internal string ActionLabel { get; set; } = string.Empty; 30 | internal Action? Action { get; set; } 31 | 32 | internal bool DismissOnClick { get; set; } 33 | 34 | internal ToastPosition? Position { get; set; } 35 | 36 | internal ToastBuilder CreateToast(string title) 37 | { 38 | _toast = new Toast(_manager) 39 | { 40 | Title = title 41 | }; 42 | return this; 43 | } 44 | 45 | internal void Show() 46 | { 47 | _toast ??= new Toast(_manager); 48 | 49 | _toast.Notification = Notification; 50 | _toast.Content = Content; 51 | _toast.Delay = Delay; 52 | _toast.ActionLabel = ActionLabel; 53 | _toast.CanDismissByClicking = DismissOnClick; 54 | _toast.Action = Action; 55 | _toast.Position = Position; 56 | _manager.Queue(_toast); 57 | } 58 | } -------------------------------------------------------------------------------- /src/ShadUI/Toasts/ToastHost.axaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 22 | -------------------------------------------------------------------------------- /src/ShadUI/Toasts/ToastManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace ShadUI.Toasts; 6 | 7 | /// 8 | /// Manages the toast notification. 9 | /// 10 | public sealed class ToastManager 11 | { 12 | internal event EventHandler? OnToastQueued; 13 | internal event EventHandler? OnToastDismissed; 14 | internal event EventHandler? OnAllToastsDismissed; 15 | 16 | private readonly List _toasts = []; 17 | 18 | internal void Queue(Toast toast) 19 | { 20 | _toasts.Add(toast); 21 | OnToastQueued?.Invoke(this, toast); 22 | } 23 | 24 | internal void Dismiss(Toast toast) 25 | { 26 | if (!_toasts.Contains(toast)) return; 27 | OnToastDismissed?.Invoke(this, toast); 28 | _toasts.Remove(toast); 29 | } 30 | 31 | private void Dismiss(int count) 32 | { 33 | if (!_toasts.Any()) return; 34 | if (count > _toasts.Count) count = _toasts.Count; 35 | for (var i = 0; i < count; i++) 36 | { 37 | var removed = _toasts[i]; 38 | OnToastDismissed?.Invoke(this, removed); 39 | _toasts.RemoveAt(i); 40 | } 41 | } 42 | 43 | internal void EnsureMaximum(int maxAllowed) 44 | { 45 | if (_toasts.Count <= maxAllowed) return; 46 | Dismiss(_toasts.Count - maxAllowed); 47 | } 48 | 49 | /// 50 | /// Dismiss all toasts. 51 | /// 52 | public void DismissAll() 53 | { 54 | if (!_toasts.Any()) return; 55 | OnAllToastsDismissed?.Invoke(this, EventArgs.Empty); 56 | _toasts.Clear(); 57 | } 58 | 59 | internal bool IsDismissed(Toast toast) => !_toasts.Contains(toast); 60 | } -------------------------------------------------------------------------------- /src/ShadUI/Toasts/ToastPosition.cs: -------------------------------------------------------------------------------- 1 | namespace ShadUI.Toasts; 2 | 3 | /// 4 | /// Defines the position of the toast. 5 | /// 6 | public enum ToastPosition 7 | { 8 | /// 9 | /// Places the toast in the bottom right corner of the screen. 10 | /// 11 | BottomRight, 12 | 13 | /// 14 | /// Places the toast in the bottom left corner of the screen. 15 | /// 16 | BottomLeft, 17 | 18 | /// 19 | /// Places the toast in the bottom center corner of the screen. 20 | /// 21 | BottomCenter, 22 | 23 | /// 24 | /// Places the toast in the top right corner of the screen. 25 | /// 26 | TopRight, 27 | 28 | /// 29 | /// Places the toast in the top left corner of the screen. 30 | /// 31 | TopLeft, 32 | 33 | /// 34 | /// Places the toast in the top center corner of the screen. 35 | /// 36 | TopCenter 37 | } -------------------------------------------------------------------------------- /src/ShadUI/Utilities/ControlAnimationHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Avalonia; 3 | using Avalonia.Animation; 4 | using Avalonia.Animation.Easings; 5 | using Avalonia.Styling; 6 | 7 | namespace ShadUI.Utilities; 8 | 9 | /// 10 | /// Provides helper methods for animating controls. 11 | /// 12 | internal static class ControlAnimationHelper 13 | { 14 | /// 15 | /// Animates a property of a control from one value to another over a specified duration. 16 | /// 17 | /// The type of the property to animate. 18 | /// The control to animate. 19 | /// The property to animate. 20 | /// The starting value of the property. 21 | /// The ending value of the property. 22 | /// The duration of the animation. 23 | /// The number of times to repeat the animation. Default is 1. 24 | public static void Animate(this Animatable control, AvaloniaProperty property, T from, T to, TimeSpan duration, 25 | ulong count = 1) 26 | { 27 | new Animation 28 | { 29 | Duration = duration, 30 | FillMode = FillMode.Forward, 31 | Easing = new CubicEaseInOut(), 32 | IterationCount = new IterationCount(count), 33 | PlaybackDirection = PlaybackDirection.Normal, 34 | Children = 35 | { 36 | new KeyFrame 37 | { 38 | Setters = { new Setter { Property = property, Value = from } }, 39 | KeyTime = TimeSpan.FromSeconds(0) 40 | }, 41 | new KeyFrame 42 | { 43 | Setters = { new Setter { Property = property, Value = to } }, 44 | KeyTime = duration 45 | } 46 | } 47 | }.RunAsync(control); 48 | } 49 | } -------------------------------------------------------------------------------- /src/ShadUI/Utilities/DataTemplateInclude.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Avalonia.Controls; 4 | using Avalonia.Controls.Templates; 5 | using Avalonia.Markup.Xaml; 6 | 7 | // ReSharper disable once CheckNamespace 8 | namespace ShadUI; 9 | 10 | /// 11 | /// Provides functionality to include and load data templates from external XAML sources. 12 | /// 13 | public class DataTemplateInclude : IDataTemplate 14 | { 15 | private DataTemplates? _loaded; 16 | private bool _isLoading; 17 | 18 | /// 19 | /// Gets or sets the source URI of the XAML file containing the data templates. 20 | /// 21 | public Uri Source { get; set; } = null!; 22 | 23 | /// 24 | /// Gets the loaded data templates collection. Templates are loaded lazily when this property is first accessed. 25 | /// 26 | /// A collection of loaded data templates, or null if loading fails. 27 | public DataTemplates? Loaded 28 | { 29 | get 30 | { 31 | if (_loaded != null) return _loaded; 32 | 33 | _isLoading = true; 34 | _loaded = (DataTemplates) AvaloniaXamlLoader.Load(Source); 35 | _isLoading = false; 36 | 37 | return _loaded; 38 | } 39 | } 40 | 41 | /// 42 | /// Initializes a new instance of the class. 43 | /// 44 | public DataTemplateInclude() 45 | { 46 | } 47 | 48 | /// 49 | /// Determines whether this template can be used to display the specified data. 50 | /// 51 | /// The data object to test. 52 | /// true if the template can be used for the specified data; otherwise, false. 53 | public bool Match(object? data) 54 | { 55 | if (_isLoading || Loaded == null) 56 | return false; 57 | 58 | return Loaded.Any(dt => dt.Match(data)); 59 | } 60 | 61 | /// 62 | /// Builds a control for the specified data object using the matching template. 63 | /// 64 | /// The data object to build a control for. 65 | /// A new control instance if a matching template is found; otherwise, null. 66 | public Control? Build(object? data) 67 | { 68 | if (_isLoading || Loaded == null) 69 | return null; 70 | 71 | return Loaded.FirstOrDefault(dt => dt.Match(data))?.Build(data); 72 | } 73 | } --------------------------------------------------------------------------------