Theme

This feature implementations configures DomainModel metadata attributes and extracts component descriptors for ui theme pages and components of an application.

Default

Default Theme feature introduces many components and sets defaults for the domain model. It also configures error pages, layouts, and pages.

To use this theme directly without any update use this;

c => c.Default(
    index: ...,
    routes: [...],
    errorPageOptions: ep => ...,
    sideMenuOptions: sm => ...,
    headerOptions: h => ...,
    debugComponentPaths: ...
)

Or you may prefer to create your custom theme on top of this default theme;

public static class CustomThemeExtensions
{
    public static CustomThemeFeature Custom(this ThemeConfigurator _) =>
        new(
        [
            // All app routes
        ]);
}

public class CustomThemeFeature(IEnumerable<Func<Router, Route>> routes)
    : DefaultThemeFeature(routes.Select(r => r(new())))
{
    public override void Configure(LayerConfigurator configurator)
    {
        // Applies default theme rules
        base.Configure(configurator);

        configurator.ConfigureDomainModelBuilder(builder =>
        {
            // Your custom conventions and page overrides
        });

        configurator.ConfigureComponentExports(c =>
        {
            // Add your component exports using your own `Components` extensions
            // c.AddFromExtensions(typeof(Components));
        });

        configurator.ConfigurePageDescriptors(pages =>
        {
            // Add other pages like `auth/login.vue` etc.
        });
    }
}

Below you can find the rules that comes with this theme. For other user experiences, see UX Feature

GroupRules
PropertyAll public properties get a DataAttribute with a camelized name and titleized label
Default component is None
string and Guid properties render with String
MethodAll actions with ActionModelAttribute get a TabAttribute
Each action is wired as a remote method with MethodRemote
ParameterParameters with ParameterModelAttribute use Parameter schema
Required and default values are taken from the attribute
EnumEnum types render inline with EnumInline
Data TableDefault rows set to 5
Paginator enabled
Export option added for methods with DataTable
Properties with DataAttribute render as DataTable.Column
Column titles use the label of the property and are exportable
Error PageError page includes safe links for routes with ErrorSafeLink
Predefined error messages:
  ↳ 403 Access Denied
  ↳ 404 Page Not Found
  ↳ 500 Unexpected Error
Messages can be customized with errorPageOptions:
LayoutsDefaultLayout includes
  ↳ Side menu with routes marked for SideMenu
  ↳ Header sitemap with enabled routes
Both side menu and header can be customized with sideMenuOptions: and headerOptions:
ModalLayout also included
PagesBuilds pages from routes using domain model and localization
Each route becomes a page if it can be resolved

routes: list is a list of builder functions that takes Router as a parameter and returns Route instance. Three types of route is supported out of the box.

r => r.Index() with { ... },
r => r.Root("/my-parent", "MyParent", "pi pi-user") with { ... },
r => r.Child("/my-parent/my-child", "MyChild", "/my-parent") with { ... },

Page Types

There are three types of page, .Implemented(), .Described(d => ...) and .Generated(g => ...). Each route has a Page property that defines what page to render at that route.

By default pages use .Implemented(), meaning you need to have a .vue page at the given route, e.g. for /my-parent route to work you need to have /pages/my-parent.vue file in the UI project.

r => r.Root("/my-parent", "MyParent", "pi pi-user") with { Page = p => p.Implemented() }

// or

r => r.Root("/my-parent", "MyParent", "pi pi-user")

.Described(d => ...) is appropriate when you decide to fully describe the page manually from your theme feature. Add an extension method to Page.Describer for your custom page and use it in routes.

r => r.Root("/my-parent", "MyParent", "pi pi-user") with { Page = p => p.Described(d => d.MyParent()) }

.Generated(g => ...) is appropriate when you have necessary conventions to generate a page descriptor out of a domain model.

r => r.Root("/my-parent", "MyParent", "pi pi-user") with { Page = p => p.Generated(g => g.From<MyParent>()) }