diff --git a/docs/guides/themes/index.html b/docs/guides/themes/index.html index d041fc8cc..d17ce7ecb 100644 --- a/docs/guides/themes/index.html +++ b/docs/guides/themes/index.html @@ -2,9 +2,9 @@ - Themes Guide (WIP) | Oqtane Docs - APIs and more for the Modular Blazor Application Framework + Oqtane Themes Guide | Oqtane Docs - APIs and more for the Modular Blazor Application Framework - + @@ -84,10 +84,12 @@
Table of Contents
-

Themes Guide (WIP)

+

Oqtane Themes Guide

+

Oqtane Themes are a way to customize the look and feel of your Oqtane website. This guide will help you get started with creating and using themes in Oqtane.

+

What is a Theme?

A theme is a collection of files that define the look and feel of your website. Themes can include CSS, JavaScript, images, and other assets that are used to style your website.

@@ -95,6 +97,7 @@

What is a Theme?

and these are compiled into a DLL that is loaded by the Oqtane framework. Here's an example:

+

 

In this example, the theme controls:

  1. Placement, size and styling of the logo - as well as how it changes in responsive scenarios.
  2. @@ -102,50 +105,32 @@

    What is a Theme?

  3. The layout of the footer, including the social media links.
  4. Font sizes and colors for various headings and normal text.
-

Parts of a Theme

-

Oqtane themes - when installed - consist of the following parts:

+

Next Steps

+

Read about:

    -
  1. A DLL file that contains the compiled Blazor components.
  2. -
  3. JS and CSS files in wwwroot/Themes/[your-theme-name].
  4. +
  5. Parts of an Oqtane Theme
  6. +
  7. Theme Distribution and Installation
  8. +
  9. Theme Code Explained
  10. +
  11. Theme Solution Explained
- -

Theme Distribution and Installation

-

Themes are usually distributed as nuget packages. -Internally such a nuget package is actually just a ZIP file.

- -

It contains:

+

Tasks to complete these guides

+

The following topics should be covered as soon as possible (help wanted!)

    -
  1. a .nuspec file containing information about it's contents
  2. -
  3. a lib folder containing the DLL file(s)
  4. -
  5. a wwwroot folder containing the JS and CSS files
  6. -
  7. an icon.png file
  8. -
  9. and some other files which are not important to us
  10. +
  11. How to create a new theme - step by step starting with the built-in assistant
  12. +
  13. How to customize an existing theme
  14. +
  15. How to install a theme
  16. +
  17. How to uninstall a theme
  18. +
  19. How to update a theme
  20. +
  21. How to create a theme from scratch
  22. +
  23. How to publish a theme in the Marketplace
  24. +
  25. Guidance for assets / resources
  26. +
  27. Guidance for render modes and edge cases / SSR .net 8.0
  28. +
  29. Guidance for responsive design
  30. +
  31. Guidance for accessibility
  32. +
  33. Guidance for performance & SEO
  34. +
  35. Best Practices for assets - especially JS/CSS
  36. +
  37. Some guidance on CSS variables / Bootstrap 5.3 conventions
- -

Theme installation works like any other module installation in Oqtane. -You can install a theme by either...

-
    -
  1. uploading the nuget package in the Modules section of the admin area
  2. -
  3. by auto-downloading it from the Oqtane marketplace
  4. -
  5. by placing it in the Packages folder of your Oqtane installation
  6. -
  7. manually copying the files to your Oqtane installation
  8. -
-

...and then restarting Oqtane.

-

Code Structure of a Theme

-

Internally a theme only needs the following 4 things:

-
    -
  1. An own namespace such as YourCompany.Themes.YourTheme.
  2. -
  3. A ThemeInfo.cs file in that namespace which implements Oqtane.Themes.ITheme.
    -This file contains information about the theme like name, author, version, etc.
  4. -
  5. A theme file like MyTheme.razor which is the main thing shown to the user.
  6. -
  7. A container file like Container.razor which is the main wrapper around a module.
  8. -
-
-
Tip
-

It is crucial that the namespace of the theme is unique, -and that all these core elements (ThemeInfo, Theme, Container) -are in exactly this namespace.

-
diff --git a/docs/guides/themes/oqtane-theme-code-explained.html b/docs/guides/themes/oqtane-theme-code-explained.html new file mode 100644 index 000000000..c11fb9dc0 --- /dev/null +++ b/docs/guides/themes/oqtane-theme-code-explained.html @@ -0,0 +1,392 @@ + + + + + Themes - Code Structure of a Theme | Oqtane Docs - APIs and more for the Modular Blazor Application Framework + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+
Table of Contents
+ +
+
+ +
+
+
+ +
+
+ + + +
+ +
+

Themes - Code Structure of a Theme

+ +

Internally a theme only needs the following 4 things:

+
    +
  1. An own namespace such as YourCompany.Themes.YourTheme.
  2. +
  3. A ThemeInfo.cs file in that namespace which implements Oqtane.Themes.ITheme.
    +This file contains information about the theme like name, author, version, etc.
  4. +
  5. A theme file like MyTheme.razor which is the main thing shown to the user.
  6. +
  7. A container file like Container.razor which is the main wrapper around a module.
  8. +
+
+
Warning
+

It is crucial that the namespace of the theme is unique, +and that all these core elements (ThemeInfo, Theme, Container) +are in exactly this namespace.

+
+

Example from the Oqtane Arsha

+

Arsha is a sample theme that comes with Oqtane. +You can find the git repo here.

+

ThemeInfo.cs

+

The ThemeInfo.cs +file is necessary to provide information about the theme. +In the code you can see it contains

+
    +
  1. The namespace of the theme - must be unique, and must match the theme/container namespace
  2. +
  3. the Name of the theme - displayed to the user
  4. +
  5. the Version of the theme
  6. +
  7. the PackageName - used for installation / differentiation
  8. +
  9. the optional ThemeSettingsType (class name) of the theme settings
  10. +
  11. the optional ContainerSettingsType (class name) of the container settings
  12. +
  13. a list of Resources - CSS and JS files that are loaded when the theme is used
    +note: the Resources can also be specified in each Theme.razor file
  14. +
+
using System.Collections.Generic;
+using Oqtane.Models;
+using Oqtane.Themes;
+using Oqtane.Shared;
+
+namespace Oqtane.Theme.Arsha
+{
+  public class ThemeInfo : ITheme
+  {
+    public Models.Theme Theme => new Models.Theme
+    {
+      Name = "Arsha",
+      Version = "1.0.0",
+      PackageName = "Oqtane.Theme.Arsha",
+      ThemeSettingsType = "Oqtane.Theme.Arsha.ThemeSettings, Oqtane.Theme.Arsha.Client.Oqtane",
+      ContainerSettingsType = "Oqtane.Theme.Arsha.ContainerSettings, Oqtane.Theme.Arsha.Client.Oqtane",
+      Resources = new List<Resource>()
+      {
+        // Google Fonts
+        new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i%7CRaleway:300,300i,400,400i,500,500i,600,600i,700,700i%7CPoppins:300,300i,400,400i,500,500i,600,600i,700,700i" },
+        // Vendor CSS Files
+        new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/assets/vendor/aos/aos.css" },
+        // ...rest of files omitted for brevity
+
+        // Template Main CSS File
+        new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/assets/css/style.css" },
+
+        // Vendor JS Files
+        new Resource { ResourceType = ResourceType.Script, Url = "~/assets/vendor/aos/aos.js", Location = ResourceLocation.Body },
+        // ...rest of files omitted for brevity
+        
+        // Template Main JS File 
+        new Resource { ResourceType = ResourceType.Script, Url = "~/assets/js/main.js", Location = ResourceLocation.Body, Reload = true, RenderMode = RenderModes.Static },
+        new Resource { ResourceType = ResourceType.Script, Url = "~/assets/js/interop.js", Location = ResourceLocation.Body, RenderMode = RenderModes.Interactive }
+      }
+    };
+  }
+}
+
+

The Theme File

+

The Theme.razor +file is the main file that is shown to the user.

+

It contains the HTML structure of the theme and can include other Blazor components. +Important things to know:

+
    +
  1. The @namespace directive must match the namespace of the theme
  2. +
  3. The @inherits directive must inherit from ThemeBase or a class that inherits from ThemeBase
  4. +
  5. The @inject directive can be used to inject services like NavigationManager or ISettingService
  6. +
  7. The @code block can contain C# code that is executed when the component is rendered
  8. +
  9. The HTML part - which is the HTML inside the <body> tag (without <head> etc.). +This "html" can be +
      +
    1. normal HTML such as div, section, h1, p, img etc.
    2. +
    3. Razor variables such as @PageState.Page.Name
    4. +
    5. Razor data from functions such as @NavigateUrl()
    6. +
    7. Razor statements such as @if or @foreach
    8. +
    9. Blazor components such as <NavMenu /> or <Login />
    10. +
    +
  10. +
+
@namespace Oqtane.Theme.Arsha
+@inherits ThemeBase
+@inject NavigationManager NavigationManager
+@inject ISettingService SettingService
+
+<!-- ======= Header ======= -->
+<header id="header" class="@_headerclass">
+  <div class="container d-flex align-items-center">
+    <!-- omited for brevity -->
+    <nav id="navbar" class="navbar">
+      <NavMenu />
+    </nav>
+    <div class="mx-3 controls-group"><UserProfile /> <Login /> <ControlPanel /></div>
+  </div>
+</header>
+<!-- End Header -->
+
+@if (!string.IsNullOrEmpty(_hero))
+{
+  <!-- ======= Hero Section ======= -->
+  @((MarkupString)_hero)
+  <!-- End Hero -->
+  <!-- ======= Main ======= -->
+  <main id="main">
+      <Pane Name="@PaneNames.Default" />
+  </main>
+  <!-- End #main -->
+}
+else
+{
+  <!-- ======= Main ======= -->
+  <main id="main">
+    <!-- ======= Breadcrumbs ======= -->
+    <section class="breadcrumbs">
+      <div class="container">
+        <h2 class="mt-2">@PageState.Page.Name</h2>
+      </div>
+    </section><!-- End Breadcrumbs -->
+    <section class="inner-page">
+      <div class="container">
+        <Pane Name="@PaneNames.Default" />
+      </div>
+    </section>
+  </main>
+  <!-- End Main -->
+}
+
+<!-- ======= Footer ======= -->
+@((MarkupString)_footer)
+<!-- End Footer -->
+
+<a href="@NavigateUrl()" class="back-to-top d-flex align-items-center justify-content-center" data-enhance-nav="false"><i class="bi bi-arrow-up-short"></i></a>
+
+@code {
+  public override string Name => "Default";
+  public override string Panes => PaneNames.Default;
+
+  private string _hero = "";
+  private string _headerclass = "";
+  private string _footer = "";
+
+  protected override async Task OnParametersSetAsync()
+  {
+    // omitted for brevity
+  }
+
+  protected override async Task OnAfterRenderAsync(bool firstRender)
+  {
+    // omitted for brevity
+  }
+
+  private string DefaultFooter
+  {
+    get
+    {
+      return 
+      "<footer id=\"footer\">\n" +
+      "   <div class=\"footer-newsletter\">\n" +
+          <!-- omitted for brevity -->
+      "   </div>\n" +
+      "</footer>\n";
+    }
+  }
+}
+
+

The Container File

+

The Container.razor +file is the main wrapper around a module. +Here's what you should know:

+
    +
  1. The @namespace directive must match the namespace of the theme
  2. +
  3. The @inherits directive must inherit from ContainerBase or a class that inherits from ContainerBase
  4. +
  5. The @inject directive can be used to inject services like ISettingService
  6. +
  7. The @code block can contain C# code that is executed when the component is rendered
  8. +
  9. The HTML parts with the same possibilities as the theme above.
  10. +
+
@namespace Oqtane.Theme.Arsha
+@inherits ContainerBase
+@inject ISettingService SettingService
+
+@if (_title)
+{
+  @if (_animate)
+  {
+    <section>
+      <div class="container" data-aos="fade-up">
+        <ModuleActions />
+        @if (ModuleState.Title != "-")
+        {
+          <div class="section-title">
+            <h2>@ModuleState.Title</h2>
+          </div>
+        }
+        <div class="row">
+          <ModuleInstance />
+        </div>
+      </div>
+    </section>
+  }
+  else
+  {
+    <!-- omitted for brevity -->
+  }
+}
+else
+{
+    <!-- omitted for brevity -->
+}
+
+@code {
+  private bool _title = true;
+  private bool _animate = false;
+
+  protected override void OnParametersSet()
+  {
+    // omitted for brevity
+  }
+}
+
+

Blazor Components

+

In addition to the required minimum files, you can also include other Blazor components. +Here's an example of the NavMenu.razor.

+

It doesn't do much, but check if the menu should show, and then calls the NavMenuItems component.

+
@namespace Oqtane.Theme.Arsha
+
+@inherits MenuBase
+
+@if (MenuPages.Any())
+{
+  <NavMenuItems ParentPage="null" Pages="MenuPages" />
+  <i class="bi bi-list mobile-nav-toggle"></i>
+}
+
+

The NavMenuItems.razor +is way more complex, as it recursively calls itself to render the menu items.

+
@namespace Oqtane.Theme.Arsha
+@inherits MenuItemsBase
+
+<ul>
+  @foreach (var childPage in GetChildPages())
+  {
+    var _attributes = new Dictionary<string, object>();
+    _attributes.Add("href", GetUrl(childPage));
+    var _target = GetTarget(childPage);
+    if (!string.IsNullOrEmpty(_target))
+        _attributes.Add("target", _target);
+
+    if (!childPage.HasChildren)
+    {
+      <!-- omitted for brevity -->
+    }
+    else
+    {
+      <li class="dropdown">
+        <a @attributes="_attributes"><span>@childPage.Name</span> 
+          @if (childPage.Level == 0)
+            <i class="bi bi-chevron-down"></i>
+          else
+            <i class="bi bi-chevron-right"></i>
+        </a>
+        <NavMenuItems ParentPage="childPage" Pages="Pages" />
+      </li>
+    }
+  }
+</ul>
+
+ +
+ + + + + +
+ +
+ +
+
+ +
+ + + + diff --git a/docs/guides/themes/oqtane-theme-code-structure.html b/docs/guides/themes/oqtane-theme-code-structure.html new file mode 100644 index 000000000..df63a52ad --- /dev/null +++ b/docs/guides/themes/oqtane-theme-code-structure.html @@ -0,0 +1,392 @@ + + + + + Themes - Code Structure of a Theme | Oqtane Docs - APIs and more for the Modular Blazor Application Framework + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+
Table of Contents
+ +
+
+ +
+
+
+ +
+
+ + + +
+ +
+

Themes - Code Structure of a Theme

+ +

Internally a theme only needs the following 4 things:

+
    +
  1. An own namespace such as YourCompany.Themes.YourTheme.
  2. +
  3. A ThemeInfo.cs file in that namespace which implements Oqtane.Themes.ITheme.
    +This file contains information about the theme like name, author, version, etc.
  4. +
  5. A theme file like MyTheme.razor which is the main thing shown to the user.
  6. +
  7. A container file like Container.razor which is the main wrapper around a module.
  8. +
+
+
Warning
+

It is crucial that the namespace of the theme is unique, +and that all these core elements (ThemeInfo, Theme, Container) +are in exactly this namespace.

+
+

Example from the Oqtane Arsha

+

Arsha is a sample theme that comes with Oqtane. +You can find the git repo here.

+

ThemeInfo.cs

+

The ThemeInfo.cs +file is necessary to provide information about the theme. +In the code you can see it contains

+
    +
  1. The namespace of the theme - must be unique, and must match the theme/container namespace
  2. +
  3. the Name of the theme - displayed to the user
  4. +
  5. the Version of the theme
  6. +
  7. the PackageName - used for installation / differentiation
  8. +
  9. the optional ThemeSettingsType (class name) of the theme settings
  10. +
  11. the optional ContainerSettingsType (class name) of the container settings
  12. +
  13. a list of Resources - CSS and JS files that are loaded when the theme is used
    +note: the Resources can also be specified in each Theme.razor file
  14. +
+
using System.Collections.Generic;
+using Oqtane.Models;
+using Oqtane.Themes;
+using Oqtane.Shared;
+
+namespace Oqtane.Theme.Arsha
+{
+  public class ThemeInfo : ITheme
+  {
+    public Models.Theme Theme => new Models.Theme
+    {
+      Name = "Arsha",
+      Version = "1.0.0",
+      PackageName = "Oqtane.Theme.Arsha",
+      ThemeSettingsType = "Oqtane.Theme.Arsha.ThemeSettings, Oqtane.Theme.Arsha.Client.Oqtane",
+      ContainerSettingsType = "Oqtane.Theme.Arsha.ContainerSettings, Oqtane.Theme.Arsha.Client.Oqtane",
+      Resources = new List<Resource>()
+      {
+        // Google Fonts
+        new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i%7CRaleway:300,300i,400,400i,500,500i,600,600i,700,700i%7CPoppins:300,300i,400,400i,500,500i,600,600i,700,700i" },
+        // Vendor CSS Files
+        new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/assets/vendor/aos/aos.css" },
+        // ...rest of files omitted for brevity
+
+        // Template Main CSS File
+        new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/assets/css/style.css" },
+
+        // Vendor JS Files
+        new Resource { ResourceType = ResourceType.Script, Url = "~/assets/vendor/aos/aos.js", Location = ResourceLocation.Body },
+        // ...rest of files omitted for brevity
+        
+        // Template Main JS File 
+        new Resource { ResourceType = ResourceType.Script, Url = "~/assets/js/main.js", Location = ResourceLocation.Body, Reload = true, RenderMode = RenderModes.Static },
+        new Resource { ResourceType = ResourceType.Script, Url = "~/assets/js/interop.js", Location = ResourceLocation.Body, RenderMode = RenderModes.Interactive }
+      }
+    };
+  }
+}
+
+

The Theme File

+

The Theme.razor +file is the main file that is shown to the user.

+

It contains the HTML structure of the theme and can include other Blazor components. +Important things to know:

+
    +
  1. The @namespace directive must match the namespace of the theme
  2. +
  3. The @inherits directive must inherit from ThemeBase or a class that inherits from ThemeBase
  4. +
  5. The @inject directive can be used to inject services like NavigationManager or ISettingService
  6. +
  7. The @code block can contain C# code that is executed when the component is rendered
  8. +
  9. The HTML part - which is the HTML inside the <body> tag (without <head> etc.). +This "html" can be +
      +
    1. normal HTML such as div, section, h1, p, img etc.
    2. +
    3. Razor variables such as @PageState.Page.Name
    4. +
    5. Razor data from functions such as @NavigateUrl()
    6. +
    7. Razor statements such as @if or @foreach
    8. +
    9. Blazor components such as <NavMenu /> or <Login />
    10. +
    +
  10. +
+
@namespace Oqtane.Theme.Arsha
+@inherits ThemeBase
+@inject NavigationManager NavigationManager
+@inject ISettingService SettingService
+
+<!-- ======= Header ======= -->
+<header id="header" class="@_headerclass">
+  <div class="container d-flex align-items-center">
+    <!-- omited for brevity -->
+    <nav id="navbar" class="navbar">
+      <NavMenu />
+    </nav>
+    <div class="mx-3 controls-group"><UserProfile /> <Login /> <ControlPanel /></div>
+  </div>
+</header>
+<!-- End Header -->
+
+@if (!string.IsNullOrEmpty(_hero))
+{
+  <!-- ======= Hero Section ======= -->
+  @((MarkupString)_hero)
+  <!-- End Hero -->
+  <!-- ======= Main ======= -->
+  <main id="main">
+      <Pane Name="@PaneNames.Default" />
+  </main>
+  <!-- End #main -->
+}
+else
+{
+  <!-- ======= Main ======= -->
+  <main id="main">
+    <!-- ======= Breadcrumbs ======= -->
+    <section class="breadcrumbs">
+      <div class="container">
+        <h2 class="mt-2">@PageState.Page.Name</h2>
+      </div>
+    </section><!-- End Breadcrumbs -->
+    <section class="inner-page">
+      <div class="container">
+        <Pane Name="@PaneNames.Default" />
+      </div>
+    </section>
+  </main>
+  <!-- End Main -->
+}
+
+<!-- ======= Footer ======= -->
+@((MarkupString)_footer)
+<!-- End Footer -->
+
+<a href="@NavigateUrl()" class="back-to-top d-flex align-items-center justify-content-center" data-enhance-nav="false"><i class="bi bi-arrow-up-short"></i></a>
+
+@code {
+  public override string Name => "Default";
+  public override string Panes => PaneNames.Default;
+
+  private string _hero = "";
+  private string _headerclass = "";
+  private string _footer = "";
+
+  protected override async Task OnParametersSetAsync()
+  {
+    // omitted for brevity
+  }
+
+  protected override async Task OnAfterRenderAsync(bool firstRender)
+  {
+    // omitted for brevity
+  }
+
+  private string DefaultFooter
+  {
+    get
+    {
+      return 
+      "<footer id=\"footer\">\n" +
+      "   <div class=\"footer-newsletter\">\n" +
+          <!-- omitted for brevity -->
+      "   </div>\n" +
+      "</footer>\n";
+    }
+  }
+}
+
+

The Container File

+

The Container.razor +file is the main wrapper around a module. +Here's what you should know:

+
    +
  1. The @namespace directive must match the namespace of the theme
  2. +
  3. The @inherits directive must inherit from ContainerBase or a class that inherits from ContainerBase
  4. +
  5. The @inject directive can be used to inject services like ISettingService
  6. +
  7. The @code block can contain C# code that is executed when the component is rendered
  8. +
  9. The HTML parts with the same possibilities as the theme above.
  10. +
+
@namespace Oqtane.Theme.Arsha
+@inherits ContainerBase
+@inject ISettingService SettingService
+
+@if (_title)
+{
+  @if (_animate)
+  {
+    <section>
+      <div class="container" data-aos="fade-up">
+        <ModuleActions />
+        @if (ModuleState.Title != "-")
+        {
+          <div class="section-title">
+            <h2>@ModuleState.Title</h2>
+          </div>
+        }
+        <div class="row">
+          <ModuleInstance />
+        </div>
+      </div>
+    </section>
+  }
+  else
+  {
+    <!-- omitted for brevity -->
+  }
+}
+else
+{
+    <!-- omitted for brevity -->
+}
+
+@code {
+  private bool _title = true;
+  private bool _animate = false;
+
+  protected override void OnParametersSet()
+  {
+    // omitted for brevity
+  }
+}
+
+

Blazor Components

+

In addition to the required minimum files, you can also include other Blazor components. +Here's an example of the NavMenu.razor.

+

It doesn't do much, but check if the menu should show, and then calls the NavMenuItems component.

+
@namespace Oqtane.Theme.Arsha
+
+@inherits MenuBase
+
+@if (MenuPages.Any())
+{
+  <NavMenuItems ParentPage="null" Pages="MenuPages" />
+  <i class="bi bi-list mobile-nav-toggle"></i>
+}
+
+

The NavMenuItems.razor +is way more complex, as it recursively calls itself to render the menu items.

+
@namespace Oqtane.Theme.Arsha
+@inherits MenuItemsBase
+
+<ul>
+  @foreach (var childPage in GetChildPages())
+  {
+    var _attributes = new Dictionary<string, object>();
+    _attributes.Add("href", GetUrl(childPage));
+    var _target = GetTarget(childPage);
+    if (!string.IsNullOrEmpty(_target))
+        _attributes.Add("target", _target);
+
+    if (!childPage.HasChildren)
+    {
+      <!-- omitted for brevity -->
+    }
+    else
+    {
+      <li class="dropdown">
+        <a @attributes="_attributes"><span>@childPage.Name</span> 
+          @if (childPage.Level == 0)
+            <i class="bi bi-chevron-down"></i>
+          else
+            <i class="bi bi-chevron-right"></i>
+        </a>
+        <NavMenuItems ParentPage="childPage" Pages="Pages" />
+      </li>
+    }
+  }
+</ul>
+
+ +
+ + + + + +
+ +
+ +
+
+ +
+ + + + diff --git a/docs/guides/themes/oqtane-theme-distribution.html b/docs/guides/themes/oqtane-theme-distribution.html new file mode 100644 index 000000000..f98a70e58 --- /dev/null +++ b/docs/guides/themes/oqtane-theme-distribution.html @@ -0,0 +1,138 @@ + + + + + Themes - Distribution and Installation | Oqtane Docs - APIs and more for the Modular Blazor Application Framework + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+
Table of Contents
+ +
+
+ +
+
+
+ +
+
+ + + +
+ +
+

Themes - Distribution and Installation

+ +

Themes are usually distributed as nuget packages. +Internally such a nuget package is actually just a ZIP file.

+ +

It contains:

+
    +
  1. a .nuspec file containing information about it's contents
  2. +
  3. a lib folder containing the DLL file(s)
  4. +
  5. a wwwroot folder containing the JS and CSS files
  6. +
  7. an icon.png file
  8. +
  9. and some other files which are not important to us
  10. +
+ +

 

+

Installation

+

Theme installation works like any other module installation in Oqtane. +You can install a theme by either...

+
    +
  1. uploading the nuget package in the Modules section of the admin area
  2. +
  3. by auto-downloading it from the Oqtane marketplace
  4. +
  5. by placing it in the Packages folder of your Oqtane installation
  6. +
  7. manually copying the files to your Oqtane installation
  8. +
+

...and then restarting Oqtane.

+ +
+ + + + + +
+ +
+ +
+
+ +
+ + + + diff --git a/docs/guides/themes/oqtane-theme-solution-explained.html b/docs/guides/themes/oqtane-theme-solution-explained.html new file mode 100644 index 000000000..c5d27ab46 --- /dev/null +++ b/docs/guides/themes/oqtane-theme-solution-explained.html @@ -0,0 +1,137 @@ + + + + + Themes - Theme Solution Explained | Oqtane Docs - APIs and more for the Modular Blazor Application Framework + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+
Table of Contents
+ +
+
+ +
+
+
+ +
+
+ + + +
+ +
+

Themes - Theme Solution Explained

+ +

A Oqtane Theme Solution is a Visual Studio project which is the basis for building a theme.

+

It will typically contain the following in one or more projects:

+
    +
  1. The basics such as the ThemeInfo.cs, the theme files and the container files.
  2. +
  3. A wwwroot folder with the CSS and JS files.
  4. +
  5. A .nuspec file to package the theme into a nuget package.
  6. +
  7. Code and specs to build / compile the result - such as package.json and webpack.config.json.
  8. +
  9. Code and specs to deploy the result - such as a .nuspec file.
  10. +
  11. An icon file, copyright information and more.
  12. +
+

In the example of the Arsha theme +you can see that the theme solution contains two projects:

+ +

 

+
    +
  1. The first one is the theme and everything it consists of
  2. +
  3. The second one is the packaging project which separates nuget-creation into a separate project.
  4. +
+
+
Tip
+

This separation of projects makes work easier, so we recommend you do the same.

+
+ +
+ + + + + +
+ +
+ +
+
+ +
+ + + + diff --git a/docs/guides/themes/parts-of-an-oqtane-theme.html b/docs/guides/themes/parts-of-an-oqtane-theme.html new file mode 100644 index 000000000..11cc17aa3 --- /dev/null +++ b/docs/guides/themes/parts-of-an-oqtane-theme.html @@ -0,0 +1,121 @@ + + + + + Themes Guide - Parts of a Theme | Oqtane Docs - APIs and more for the Modular Blazor Application Framework + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+
+
Table of Contents
+ +
+
+ +
+
+
+ +
+
+ + + +
+ +
+

Themes Guide - Parts of a Theme

+ +

Oqtane themes - when installed - consist of the following core parts:

+
    +
  1. A DLL file that contains the compiled Blazor components.
  2. +
  3. JS and CSS files in wwwroot/Themes/[your-theme-name].
  4. +
+ + +
+ + + + + +
+ +
+ +
+
+ +
+ + + + diff --git a/docs/index.json b/docs/index.json index 19343b4e1..fdb30583d 100644 --- a/docs/index.json +++ b/docs/index.json @@ -2051,8 +2051,28 @@ }, "guides/themes/index.html": { "href": "guides/themes/index.html", - "title": "Themes Guide (WIP) | Oqtane Docs - APIs and more for the Modular Blazor Application Framework", - "keywords": "Themes Guide (WIP) Oqtane Themes are a way to customize the look and feel of your Oqtane website. This guide will help you get started with creating and using themes in Oqtane. What is a Theme? A theme is a collection of files that define the look and feel of your website. Themes can include CSS, JavaScript, images, and other assets that are used to style your website. Since Oqtane is based on .net and Blazor, themes are built using Blazor components and these are compiled into a DLL that is loaded by the Oqtane framework. Here's an example: In this example, the theme controls: Placement, size and styling of the logo - as well as how it changes in responsive scenarios. The layout of the main menu, including the dropdowns. The layout of the footer, including the social media links. Font sizes and colors for various headings and normal text. Parts of a Theme Oqtane themes - when installed - consist of the following parts: A DLL file that contains the compiled Blazor components. JS and CSS files in wwwroot/Themes/[your-theme-name]. Theme Distribution and Installation Themes are usually distributed as nuget packages. Internally such a nuget package is actually just a ZIP file. It contains: a .nuspec file containing information about it's contents a lib folder containing the DLL file(s) a wwwroot folder containing the JS and CSS files an icon.png file and some other files which are not important to us Theme installation works like any other module installation in Oqtane. You can install a theme by either... uploading the nuget package in the Modules section of the admin area by auto-downloading it from the Oqtane marketplace by placing it in the Packages folder of your Oqtane installation manually copying the files to your Oqtane installation ...and then restarting Oqtane. Code Structure of a Theme Internally a theme only needs the following 4 things: An own namespace such as YourCompany.Themes.YourTheme. A ThemeInfo.cs file in that namespace which implements Oqtane.Themes.ITheme. This file contains information about the theme like name, author, version, etc. A theme file like MyTheme.razor which is the main thing shown to the user. A container file like Container.razor which is the main wrapper around a module. Tip It is crucial that the namespace of the theme is unique, and that all these core elements (ThemeInfo, Theme, Container) are in exactly this namespace." + "title": "Oqtane Themes Guide | Oqtane Docs - APIs and more for the Modular Blazor Application Framework", + "keywords": "Oqtane Themes Guide Oqtane Themes are a way to customize the look and feel of your Oqtane website. This guide will help you get started with creating and using themes in Oqtane. What is a Theme? A theme is a collection of files that define the look and feel of your website. Themes can include CSS, JavaScript, images, and other assets that are used to style your website. Since Oqtane is based on .net and Blazor, themes are built using Blazor components and these are compiled into a DLL that is loaded by the Oqtane framework. Here's an example: In this example, the theme controls: Placement, size and styling of the logo - as well as how it changes in responsive scenarios. The layout of the main menu, including the dropdowns. The layout of the footer, including the social media links. Font sizes and colors for various headings and normal text. Next Steps Read about: Parts of an Oqtane Theme Theme Distribution and Installation Theme Code Explained Theme Solution Explained Tasks to complete these guides The following topics should be covered as soon as possible (help wanted!) How to create a new theme - step by step starting with the built-in assistant How to customize an existing theme How to install a theme How to uninstall a theme How to update a theme How to create a theme from scratch How to publish a theme in the Marketplace Guidance for assets / resources Guidance for render modes and edge cases / SSR .net 8.0 Guidance for responsive design Guidance for accessibility Guidance for performance & SEO Best Practices for assets - especially JS/CSS Some guidance on CSS variables / Bootstrap 5.3 conventions" + }, + "guides/themes/oqtane-theme-code-explained.html": { + "href": "guides/themes/oqtane-theme-code-explained.html", + "title": "Themes - Code Structure of a Theme | Oqtane Docs - APIs and more for the Modular Blazor Application Framework", + "keywords": "Themes - Code Structure of a Theme Internally a theme only needs the following 4 things: An own namespace such as YourCompany.Themes.YourTheme. A ThemeInfo.cs file in that namespace which implements Oqtane.Themes.ITheme. This file contains information about the theme like name, author, version, etc. A theme file like MyTheme.razor which is the main thing shown to the user. A container file like Container.razor which is the main wrapper around a module. Warning It is crucial that the namespace of the theme is unique, and that all these core elements (ThemeInfo, Theme, Container) are in exactly this namespace. Example from the Oqtane Arsha Arsha is a sample theme that comes with Oqtane. You can find the git repo here. ThemeInfo.cs The ThemeInfo.cs file is necessary to provide information about the theme. In the code you can see it contains The namespace of the theme - must be unique, and must match the theme/container namespace the Name of the theme - displayed to the user the Version of the theme the PackageName - used for installation / differentiation the optional ThemeSettingsType (class name) of the theme settings the optional ContainerSettingsType (class name) of the container settings a list of Resources - CSS and JS files that are loaded when the theme is used note: the Resources can also be specified in each Theme.razor file using System.Collections.Generic; using Oqtane.Models; using Oqtane.Themes; using Oqtane.Shared; namespace Oqtane.Theme.Arsha { public class ThemeInfo : ITheme { public Models.Theme Theme => new Models.Theme { Name = \"Arsha\", Version = \"1.0.0\", PackageName = \"Oqtane.Theme.Arsha\", ThemeSettingsType = \"Oqtane.Theme.Arsha.ThemeSettings, Oqtane.Theme.Arsha.Client.Oqtane\", ContainerSettingsType = \"Oqtane.Theme.Arsha.ContainerSettings, Oqtane.Theme.Arsha.Client.Oqtane\", Resources = new List() { // Google Fonts new Resource { ResourceType = ResourceType.Stylesheet, Url = \"https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i%7CRaleway:300,300i,400,400i,500,500i,600,600i,700,700i%7CPoppins:300,300i,400,400i,500,500i,600,600i,700,700i\" }, // Vendor CSS Files new Resource { ResourceType = ResourceType.Stylesheet, Url = \"~/assets/vendor/aos/aos.css\" }, // ...rest of files omitted for brevity // Template Main CSS File new Resource { ResourceType = ResourceType.Stylesheet, Url = \"~/assets/css/style.css\" }, // Vendor JS Files new Resource { ResourceType = ResourceType.Script, Url = \"~/assets/vendor/aos/aos.js\", Location = ResourceLocation.Body }, // ...rest of files omitted for brevity // Template Main JS File new Resource { ResourceType = ResourceType.Script, Url = \"~/assets/js/main.js\", Location = ResourceLocation.Body, Reload = true, RenderMode = RenderModes.Static }, new Resource { ResourceType = ResourceType.Script, Url = \"~/assets/js/interop.js\", Location = ResourceLocation.Body, RenderMode = RenderModes.Interactive } } }; } } The Theme File The Theme.razor file is the main file that is shown to the user. It contains the HTML structure of the theme and can include other Blazor components. Important things to know: The @namespace directive must match the namespace of the theme The @inherits directive must inherit from ThemeBase or a class that inherits from ThemeBase The @inject directive can be used to inject services like NavigationManager or ISettingService The @code block can contain C# code that is executed when the component is rendered The HTML part - which is the HTML inside the tag (without etc.). This \"html\" can be normal HTML such as div, section, h1, p, img etc. Razor variables such as @PageState.Page.Name Razor data from functions such as @NavigateUrl() Razor statements such as @if or @foreach Blazor components such as or @namespace Oqtane.Theme.Arsha @inherits ThemeBase @inject NavigationManager NavigationManager @inject ISettingService SettingService
@if (!string.IsNullOrEmpty(_hero)) { @((MarkupString)_hero)
} else {

@PageState.Page.Name

} @((MarkupString)_footer) @code { public override string Name => \"Default\"; public override string Panes => PaneNames.Default; private string _hero = \"\"; private string _headerclass = \"\"; private string _footer = \"\"; protected override async Task OnParametersSetAsync() { // omitted for brevity } protected override async Task OnAfterRenderAsync(bool firstRender) { // omitted for brevity } private string DefaultFooter { get { return \"
\\n\" + \"
\\n\" + \"
\\n\" + \"
\\n\"; } } } The Container File The Container.razor file is the main wrapper around a module. Here's what you should know: The @namespace directive must match the namespace of the theme The @inherits directive must inherit from ContainerBase or a class that inherits from ContainerBase The @inject directive can be used to inject services like ISettingService The @code block can contain C# code that is executed when the component is rendered The HTML parts with the same possibilities as the theme above. @namespace Oqtane.Theme.Arsha @inherits ContainerBase @inject ISettingService SettingService @if (_title) { @if (_animate) {
@if (ModuleState.Title != \"-\") {

@ModuleState.Title

}
} else { } } else { } @code { private bool _title = true; private bool _animate = false; protected override void OnParametersSet() { // omitted for brevity } } Blazor Components In addition to the required minimum files, you can also include other Blazor components. Here's an example of the NavMenu.razor. It doesn't do much, but check if the menu should show, and then calls the NavMenuItems component. @namespace Oqtane.Theme.Arsha @inherits MenuBase @if (MenuPages.Any()) { } The NavMenuItems.razor is way more complex, as it recursively calls itself to render the menu items. @namespace Oqtane.Theme.Arsha @inherits MenuItemsBase
    @foreach (var childPage in GetChildPages()) { var _attributes = new Dictionary(); _attributes.Add(\"href\", GetUrl(childPage)); var _target = GetTarget(childPage); if (!string.IsNullOrEmpty(_target)) _attributes.Add(\"target\", _target); if (!childPage.HasChildren) { } else {
  • @childPage.Name @if (childPage.Level == 0) else
  • } }
" + }, + "guides/themes/oqtane-theme-distribution.html": { + "href": "guides/themes/oqtane-theme-distribution.html", + "title": "Themes - Distribution and Installation | Oqtane Docs - APIs and more for the Modular Blazor Application Framework", + "keywords": "Themes - Distribution and Installation Themes are usually distributed as nuget packages. Internally such a nuget package is actually just a ZIP file. It contains: a .nuspec file containing information about it's contents a lib folder containing the DLL file(s) a wwwroot folder containing the JS and CSS files an icon.png file and some other files which are not important to us Installation Theme installation works like any other module installation in Oqtane. You can install a theme by either... uploading the nuget package in the Modules section of the admin area by auto-downloading it from the Oqtane marketplace by placing it in the Packages folder of your Oqtane installation manually copying the files to your Oqtane installation ...and then restarting Oqtane." + }, + "guides/themes/oqtane-theme-solution-explained.html": { + "href": "guides/themes/oqtane-theme-solution-explained.html", + "title": "Themes - Theme Solution Explained | Oqtane Docs - APIs and more for the Modular Blazor Application Framework", + "keywords": "Themes - Theme Solution Explained A Oqtane Theme Solution is a Visual Studio project which is the basis for building a theme. It will typically contain the following in one or more projects: The basics such as the ThemeInfo.cs, the theme files and the container files. A wwwroot folder with the CSS and JS files. A .nuspec file to package the theme into a nuget package. Code and specs to build / compile the result - such as package.json and webpack.config.json. Code and specs to deploy the result - such as a .nuspec file. An icon file, copyright information and more. In the example of the Arsha theme you can see that the theme solution contains two projects: The first one is the theme and everything it consists of The second one is the packaging project which separates nuget-creation into a separate project. Tip This separation of projects makes work easier, so we recommend you do the same." + }, + "guides/themes/parts-of-an-oqtane-theme.html": { + "href": "guides/themes/parts-of-an-oqtane-theme.html", + "title": "Themes Guide - Parts of a Theme | Oqtane Docs - APIs and more for the Modular Blazor Application Framework", + "keywords": "Themes Guide - Parts of a Theme Oqtane themes - when installed - consist of the following core parts: A DLL file that contains the compiled Blazor components. JS and CSS files in wwwroot/Themes/[your-theme-name]." }, "index.html": { "href": "index.html", diff --git a/docs/manifest.json b/docs/manifest.json index 343559131..c57a0197b 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -4479,6 +4479,16 @@ }, "version": "" }, + { + "type": "Resource", + "source_relative_path": "pages/guides/themes/assets/oqtane-theme-solution.jpg", + "output": { + "resource": { + "relative_path": "pages/guides/themes/assets/oqtane-theme-solution.jpg" + } + }, + "version": "" + }, { "type": "Conceptual", "source_relative_path": "pages/guides/themes/index.md", @@ -4489,6 +4499,59 @@ }, "version": "" }, + { + "type": "Conceptual", + "source_relative_path": "pages/guides/themes/oqtane-theme-code-explained.md", + "output": { + ".html": { + "relative_path": "guides/themes/oqtane-theme-code-explained.html" + } + }, + "version": "" + }, + { + "type": "Conceptual", + "source_relative_path": "pages/guides/themes/oqtane-theme-distribution.md", + "output": { + ".html": { + "relative_path": "guides/themes/oqtane-theme-distribution.html" + } + }, + "version": "" + }, + { + "type": "Conceptual", + "source_relative_path": "pages/guides/themes/oqtane-theme-solution-explained.md", + "output": { + ".html": { + "relative_path": "guides/themes/oqtane-theme-solution-explained.html" + } + }, + "version": "" + }, + { + "type": "Conceptual", + "source_relative_path": "pages/guides/themes/parts-of-an-oqtane-theme.md", + "output": { + ".html": { + "relative_path": "guides/themes/parts-of-an-oqtane-theme.html" + } + }, + "version": "" + }, + { + "type": "Toc", + "source_relative_path": "pages/guides/themes/toc.yml", + "output": { + ".html": { + "relative_path": "pages/guides/themes/toc.html" + }, + ".json": { + "relative_path": "pages/guides/themes/toc.json" + } + }, + "version": "" + }, { "type": "Toc", "source_relative_path": "pages/guides/toc.yml", diff --git a/docs/pages/guides/themes/assets/oqtane-theme-solution.jpg b/docs/pages/guides/themes/assets/oqtane-theme-solution.jpg new file mode 100644 index 000000000..eef0ba1b8 Binary files /dev/null and b/docs/pages/guides/themes/assets/oqtane-theme-solution.jpg differ diff --git a/docs/pages/guides/themes/toc.html b/docs/pages/guides/themes/toc.html new file mode 100644 index 000000000..f84b09bfd --- /dev/null +++ b/docs/pages/guides/themes/toc.html @@ -0,0 +1,34 @@ + + diff --git a/docs/pages/guides/themes/toc.json b/docs/pages/guides/themes/toc.json new file mode 100644 index 000000000..579128195 --- /dev/null +++ b/docs/pages/guides/themes/toc.json @@ -0,0 +1,2 @@ + +{"order":100,"items":[{"name":"Oqtane Themes Guide","href":"../../../guides/themes/index.html","topicHref":"../../../guides/themes/index.html"},{"name":"Parts of an Oqtane Theme","href":"../../../guides/themes/parts-of-an-oqtane-theme.html","topicHref":"../../../guides/themes/parts-of-an-oqtane-theme.html"},{"name":"Distribution and Installation","href":"../../../guides/themes/oqtane-theme-distribution.html","topicHref":"../../../guides/themes/oqtane-theme-distribution.html"},{"name":"Theme Code Explained","href":"../../../guides/themes/oqtane-theme-code-explained.html","topicHref":"../../../guides/themes/oqtane-theme-code-explained.html"},{"name":"Theme Solution Explained","href":"../../../guides/themes/oqtane-theme-solution-explained.html","topicHref":"../../../guides/themes/oqtane-theme-solution-explained.html"}]} diff --git a/docs/pages/guides/toc.html b/docs/pages/guides/toc.html index 7e1c3aed4..17fd2b5ca 100644 --- a/docs/pages/guides/toc.html +++ b/docs/pages/guides/toc.html @@ -32,7 +32,26 @@
  • + Themes + +
  • Roadmap & History diff --git a/docs/pages/guides/toc.json b/docs/pages/guides/toc.json index 9946a1a04..18447eacc 100644 --- a/docs/pages/guides/toc.json +++ b/docs/pages/guides/toc.json @@ -1,2 +1,2 @@ -{"items":[{"name":"Guides Home","href":"../../guides/index.html","topicHref":"../../guides/index.html"},{"name":"Concepts","href":"../../guides/concepts/index.html","topicHref":"../../guides/concepts/index.html","includedFrom":"~/pages/guides/concepts/toc.yml","items":[{"name":"Concepts","href":"../../guides/concepts/index.html","topicHref":"../../guides/concepts/index.html"},{"name":"DLL Handling","href":"../../guides/concepts/dll-handling.html","topicHref":"../../guides/concepts/dll-handling.html"},{"name":"404 Page Behavior","href":"../../guides/concepts/404-page-behavior.html","topicHref":"../../guides/concepts/404-page-behavior.html"}]},{"name":"Themes","href":"../../guides/themes/index.html","topicHref":"../../guides/themes/index.html"},{"name":"Roadmap & History","href":"../../guides/roadmap/index.html","topicHref":"../../guides/roadmap/index.html","topicUid":"Guides.Roadmap.Index"},{"name":" "},{"name":"Documentation","href":"../../guides/docs/index.html","topicHref":"../../guides/docs/index.html","includedFrom":"~/pages/guides/docs/toc.yml","items":[{"name":"Get Started","href":"../../guides/docs/build.html","topicHref":"../../guides/docs/build.html","items":[{"name":"Run Docs on Local IIS","href":"../../guides/docs/run-in-iis.html","topicHref":"../../guides/docs/run-in-iis.html"}]},{"name":"How DocFx Works","href":"../../guides/docs/how-it-works.html","topicHref":"../../guides/docs/how-it-works.html","items":[{"name":"Folders and Files","href":"../../guides/docs/folders.html","topicHref":"../../guides/docs/folders.html"},{"name":"About the API TOC","href":"../../guides/docs/api-menu.html","topicHref":"../../guides/docs/api-menu.html"}]},{"name":"The Docs Project","href":"../../guides/docs/project.html","topicHref":"../../guides/docs/project.html"},{"name":"Contribute","items":[{"name":"Markdown Tips","href":"../../guides/docs/markdown.html","topicHref":"../../guides/docs/markdown.html"},{"name":"Document Code","href":"../../guides/docs/code.html","topicHref":"../../guides/docs/code.html"},{"name":"Oqtane Docs Conventions","href":"../../guides/docs/conventions.html","topicHref":"../../guides/docs/conventions.html"},{"name":"Tips","href":"../../guides/docs/tips/index.html","topicHref":"../../guides/docs/tips/index.html"}]}]}]} +{"items":[{"name":"Guides Home","href":"../../guides/index.html","topicHref":"../../guides/index.html"},{"name":"Concepts","href":"../../guides/concepts/index.html","topicHref":"../../guides/concepts/index.html","includedFrom":"~/pages/guides/concepts/toc.yml","items":[{"name":"Concepts","href":"../../guides/concepts/index.html","topicHref":"../../guides/concepts/index.html"},{"name":"DLL Handling","href":"../../guides/concepts/dll-handling.html","topicHref":"../../guides/concepts/dll-handling.html"},{"name":"404 Page Behavior","href":"../../guides/concepts/404-page-behavior.html","topicHref":"../../guides/concepts/404-page-behavior.html"}]},{"name":"Themes","href":"../../guides/themes/index.html","topicHref":"../../guides/themes/index.html","includedFrom":"~/pages/guides/themes/toc.yml","items":[{"name":"Oqtane Themes Guide","href":"../../guides/themes/index.html","topicHref":"../../guides/themes/index.html"},{"name":"Parts of an Oqtane Theme","href":"../../guides/themes/parts-of-an-oqtane-theme.html","topicHref":"../../guides/themes/parts-of-an-oqtane-theme.html"},{"name":"Distribution and Installation","href":"../../guides/themes/oqtane-theme-distribution.html","topicHref":"../../guides/themes/oqtane-theme-distribution.html"},{"name":"Theme Code Explained","href":"../../guides/themes/oqtane-theme-code-explained.html","topicHref":"../../guides/themes/oqtane-theme-code-explained.html"},{"name":"Theme Solution Explained","href":"../../guides/themes/oqtane-theme-solution-explained.html","topicHref":"../../guides/themes/oqtane-theme-solution-explained.html"}]},{"name":"Roadmap & History","href":"../../guides/roadmap/index.html","topicHref":"../../guides/roadmap/index.html","topicUid":"Guides.Roadmap.Index"},{"name":" "},{"name":"Documentation","href":"../../guides/docs/index.html","topicHref":"../../guides/docs/index.html","includedFrom":"~/pages/guides/docs/toc.yml","items":[{"name":"Get Started","href":"../../guides/docs/build.html","topicHref":"../../guides/docs/build.html","items":[{"name":"Run Docs on Local IIS","href":"../../guides/docs/run-in-iis.html","topicHref":"../../guides/docs/run-in-iis.html"}]},{"name":"How DocFx Works","href":"../../guides/docs/how-it-works.html","topicHref":"../../guides/docs/how-it-works.html","items":[{"name":"Folders and Files","href":"../../guides/docs/folders.html","topicHref":"../../guides/docs/folders.html"},{"name":"About the API TOC","href":"../../guides/docs/api-menu.html","topicHref":"../../guides/docs/api-menu.html"}]},{"name":"The Docs Project","href":"../../guides/docs/project.html","topicHref":"../../guides/docs/project.html"},{"name":"Contribute","items":[{"name":"Markdown Tips","href":"../../guides/docs/markdown.html","topicHref":"../../guides/docs/markdown.html"},{"name":"Document Code","href":"../../guides/docs/code.html","topicHref":"../../guides/docs/code.html"},{"name":"Oqtane Docs Conventions","href":"../../guides/docs/conventions.html","topicHref":"../../guides/docs/conventions.html"},{"name":"Tips","href":"../../guides/docs/tips/index.html","topicHref":"../../guides/docs/tips/index.html"}]}]}]} diff --git a/docs/xrefmap.yml b/docs/xrefmap.yml index c8a811423..d738a4984 100644 --- a/docs/xrefmap.yml +++ b/docs/xrefmap.yml @@ -2,7 +2,7 @@ sorted: true references: - uid: Guides..Themes.Index - name: Themes Guide (WIP) + name: Oqtane Themes Guide href: guides/themes/index.html - uid: Guides.Index name: Guides WIP diff --git a/src/pages/guides/themes/assets/oqtane-theme-solution.jpg b/src/pages/guides/themes/assets/oqtane-theme-solution.jpg new file mode 100644 index 000000000..eef0ba1b8 Binary files /dev/null and b/src/pages/guides/themes/assets/oqtane-theme-solution.jpg differ diff --git a/src/pages/guides/themes/index.md b/src/pages/guides/themes/index.md index 7406b3bd1..93e0c1b76 100644 --- a/src/pages/guides/themes/index.md +++ b/src/pages/guides/themes/index.md @@ -2,7 +2,7 @@ uid: Guides..Themes.Index --- -# Themes Guide (WIP) +# Oqtane Themes Guide > Oqtane Themes are a way to customize the look and feel of your Oqtane website. > This guide will help you get started with creating and using themes in Oqtane. @@ -18,6 +18,8 @@ Here's an example: +  + In this example, the theme controls: 1. Placement, size and styling of the logo - as well as how it changes in responsive scenarios. @@ -25,54 +27,30 @@ In this example, the theme controls: 3. The layout of the footer, including the social media links. 4. Font sizes and colors for various headings and normal text. -## Parts of a Theme - -Oqtane themes - when installed - consist of the following parts: - -1. A DLL file that contains the compiled Blazor components. -2. JS and CSS files in `wwwroot/Themes/[your-theme-name]`. - - - -## Theme Distribution and Installation - -Themes are usually distributed as nuget packages. -Internally such a nuget package is actually just a ZIP file. - - - -It contains: - -1. a `.nuspec` file containing information about it's contents -2. a `lib` folder containing the DLL file(s) -3. a `wwwroot` folder containing the JS and CSS files -4. an `icon.png` file -5. and some other files which are not important to us - - - -Theme installation works like any other module installation in Oqtane. -You can install a theme by either... - -1. uploading the nuget package in the Modules section of the admin area -2. by auto-downloading it from the Oqtane marketplace -3. by placing it in the `Packages` folder of your Oqtane installation -4. manually copying the files to your Oqtane installation - -...and then restarting Oqtane. - -## Code Structure of a Theme - -Internally a theme only needs the following 4 things: - -1. An own namespace such as `YourCompany.Themes.YourTheme`. -1. A `ThemeInfo.cs` file in that namespace which implements `Oqtane.Themes.ITheme`. - This file contains information about the theme like name, author, version, etc. -1. A theme file like `MyTheme.razor` which is the main thing shown to the user. -1. A container file like `Container.razor` which is the main wrapper around a module. - -> [!TIP] -> It is crucial that the namespace of the theme is unique, -> and that all these core elements (ThemeInfo, Theme, Container) -> are in _exactly_ this namespace. - +## Next Steps + +Read about: + +1. [Parts of an Oqtane Theme](./parts-of-an-oqtane-theme.md) +1. [Theme Distribution and Installation](./oqtane-theme-distribution.md) +1. [Theme Code Explained](./oqtane-theme-code-explained) +1. [Theme Solution Explained](./oqtane-theme-solution-explained.md) + +## Tasks to complete these guides + +The following topics should be covered as soon as possible (help wanted!) + +1. How to create a new theme - step by step starting with the built-in assistant +1. How to customize an existing theme +1. How to install a theme +1. How to uninstall a theme +1. How to update a theme +1. How to create a theme from scratch +1. How to publish a theme in the [Marketplace](https://www.oqtane.net/) +1. Guidance for assets / resources +1. Guidance for render modes and edge cases / SSR .net 8.0 +1. Guidance for responsive design +1. Guidance for accessibility +1. Guidance for performance & SEO +1. Best Practices for assets - especially JS/CSS +1. Some guidance on CSS variables / Bootstrap 5.3 conventions diff --git a/src/pages/guides/themes/oqtane-theme-code-explained.md b/src/pages/guides/themes/oqtane-theme-code-explained.md new file mode 100644 index 000000000..44fe98c47 --- /dev/null +++ b/src/pages/guides/themes/oqtane-theme-code-explained.md @@ -0,0 +1,300 @@ +--- +uid: Guides..Themes.Index +--- + +# Themes - Code Structure of a Theme + +Internally a theme only needs the following 4 things: + +1. An own namespace such as `YourCompany.Themes.YourTheme`. +1. A `ThemeInfo.cs` file in that namespace which implements `Oqtane.Themes.ITheme`. + This file contains information about the theme like name, author, version, etc. +1. A theme file like `MyTheme.razor` which is the main thing shown to the user. +1. A container file like `Container.razor` which is the main wrapper around a module. + +> [!WARNING] +> It is crucial that the namespace of the theme is unique, +> and that all these core elements (ThemeInfo, Theme, Container) +> are in _exactly_ this namespace. + +## Example from the Oqtane Arsha + +**Arsha** is a sample theme that comes with Oqtane. +You can find the [git repo here](https://github.com/oqtane/Oqtane.Theme.Arsha). + +### ThemeInfo.cs + +The [ThemeInfo.cs](https://github.com/oqtane/Oqtane.Theme.Arsha/blob/main/Client/ThemeInfo.cs) +file is necessary to provide information about the theme. +In the code you can see it contains + +1. The `namespace` of the theme - must be unique, and must match the theme/container namespace +1. the `Name` of the theme - displayed to the user +1. the `Version` of the theme +1. the `PackageName` - used for installation / differentiation +1. the _optional_ `ThemeSettingsType` (class name) of the theme settings +1. the _optional_ `ContainerSettingsType` (class name) of the container settings +1. a list of `Resources` - CSS and JS files that are loaded when the theme is used + _note: the `Resources` can also be specified in each `Theme.razor` file_ + +```csharp +using System.Collections.Generic; +using Oqtane.Models; +using Oqtane.Themes; +using Oqtane.Shared; + +namespace Oqtane.Theme.Arsha +{ + public class ThemeInfo : ITheme + { + public Models.Theme Theme => new Models.Theme + { + Name = "Arsha", + Version = "1.0.0", + PackageName = "Oqtane.Theme.Arsha", + ThemeSettingsType = "Oqtane.Theme.Arsha.ThemeSettings, Oqtane.Theme.Arsha.Client.Oqtane", + ContainerSettingsType = "Oqtane.Theme.Arsha.ContainerSettings, Oqtane.Theme.Arsha.Client.Oqtane", + Resources = new List() + { + // Google Fonts + new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i%7CRaleway:300,300i,400,400i,500,500i,600,600i,700,700i%7CPoppins:300,300i,400,400i,500,500i,600,600i,700,700i" }, + // Vendor CSS Files + new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/assets/vendor/aos/aos.css" }, + // ...rest of files omitted for brevity + + // Template Main CSS File + new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/assets/css/style.css" }, + + // Vendor JS Files + new Resource { ResourceType = ResourceType.Script, Url = "~/assets/vendor/aos/aos.js", Location = ResourceLocation.Body }, + // ...rest of files omitted for brevity + + // Template Main JS File + new Resource { ResourceType = ResourceType.Script, Url = "~/assets/js/main.js", Location = ResourceLocation.Body, Reload = true, RenderMode = RenderModes.Static }, + new Resource { ResourceType = ResourceType.Script, Url = "~/assets/js/interop.js", Location = ResourceLocation.Body, RenderMode = RenderModes.Interactive } + } + }; + } +} +``` + +## The Theme File + +The [Theme.razor](https://github.com/oqtane/Oqtane.Theme.Arsha/blob/main/Client/Themes/Default.razor) +file is the main file that is shown to the user. + +It contains the HTML structure of the theme and can include other Blazor components. +Important things to know: + +1. The `@namespace` directive must match the namespace of the theme +1. The `@inherits` directive must inherit from `ThemeBase` or a class that inherits from `ThemeBase` +1. The `@inject` directive can be used to inject services like `NavigationManager` or `ISettingService` +1. The `@code` block can contain C# code that is executed when the component is rendered +1. The HTML part - which is the HTML inside the `` tag (without `` etc.). + This "html" can be + 1. normal HTML such as `div`, `section`, `h1`, `p`, `img` etc. + 1. Razor variables such as `@PageState.Page.Name` + 1. Razor data from functions such as `@NavigateUrl()` + 1. Razor statements such as `@if` or `@foreach` + 1. Blazor components such as `` or `` + + +```html +@namespace Oqtane.Theme.Arsha +@inherits ThemeBase +@inject NavigationManager NavigationManager +@inject ISettingService SettingService + + + + + +@if (!string.IsNullOrEmpty(_hero)) +{ + + @((MarkupString)_hero) + + +
    + +
    + +} +else +{ + +
    + + +
    +
    + +
    +
    +
    + +} + + +@((MarkupString)_footer) + + + + +@code { + public override string Name => "Default"; + public override string Panes => PaneNames.Default; + + private string _hero = ""; + private string _headerclass = ""; + private string _footer = ""; + + protected override async Task OnParametersSetAsync() + { + // omitted for brevity + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + // omitted for brevity + } + + private string DefaultFooter + { + get + { + return + "
    \n" + + "
    \n" + + + "
    \n" + + "
    \n"; + } + } +} +``` + +## The Container File + +The [Container.razor](https://github.com/oqtane/Oqtane.Theme.Arsha/blob/main/Client/Containers/Container.razor) +file is the main wrapper around a module. +Here's what you should know: + +1. The `@namespace` directive must match the namespace of the theme +1. The `@inherits` directive must inherit from `ContainerBase` or a class that inherits from `ContainerBase` +1. The `@inject` directive can be used to inject services like `ISettingService` +1. The `@code` block can contain C# code that is executed when the component is rendered +1. The HTML parts with the same possibilities as the theme above. + +```html +@namespace Oqtane.Theme.Arsha +@inherits ContainerBase +@inject ISettingService SettingService + +@if (_title) +{ + @if (_animate) + { +
    +
    + + @if (ModuleState.Title != "-") + { +
    +

    @ModuleState.Title

    +
    + } +
    + +
    +
    +
    + } + else + { + + } +} +else +{ + +} + +@code { + private bool _title = true; + private bool _animate = false; + + protected override void OnParametersSet() + { + // omitted for brevity + } +} +``` + +## Blazor Components + +In addition to the required minimum files, you can also include other Blazor components. +Here's an example of the [NavMenu.razor](https://github.com/oqtane/Oqtane.Theme.Arsha/blob/main/Client/Components/NavMenu.razor). + +It doesn't do much, but check if the menu should show, and then calls the `NavMenuItems` component. + +```html +@namespace Oqtane.Theme.Arsha + +@inherits MenuBase + +@if (MenuPages.Any()) +{ + + +} +``` + +The [NavMenuItems.razor](https://github.com/oqtane/Oqtane.Theme.Arsha/blob/main/Client/Components/NavMenuItems.razor) +is way more complex, as it recursively calls itself to render the menu items. + +```html +@namespace Oqtane.Theme.Arsha +@inherits MenuItemsBase + +
      + @foreach (var childPage in GetChildPages()) + { + var _attributes = new Dictionary(); + _attributes.Add("href", GetUrl(childPage)); + var _target = GetTarget(childPage); + if (!string.IsNullOrEmpty(_target)) + _attributes.Add("target", _target); + + if (!childPage.HasChildren) + { + + } + else + { + + } + } +
    +``` + diff --git a/src/pages/guides/themes/oqtane-theme-distribution.md b/src/pages/guides/themes/oqtane-theme-distribution.md new file mode 100644 index 000000000..0adaf77f2 --- /dev/null +++ b/src/pages/guides/themes/oqtane-theme-distribution.md @@ -0,0 +1,34 @@ +--- +uid: Guides..Themes.Index +--- + +# Themes - Distribution and Installation + +Themes are usually distributed as nuget packages. +Internally such a nuget package is actually just a ZIP file. + + + +It contains: + +1. a `.nuspec` file containing information about it's contents +2. a `lib` folder containing the DLL file(s) +3. a `wwwroot` folder containing the JS and CSS files +4. an `icon.png` file +5. and some other files which are not important to us + + + +  + +## Installation + +Theme installation works like any other module installation in Oqtane. +You can install a theme by either... + +1. uploading the nuget package in the Modules section of the admin area +2. by auto-downloading it from the Oqtane marketplace +3. by placing it in the `Packages` folder of your Oqtane installation +4. manually copying the files to your Oqtane installation + +...and then restarting Oqtane. diff --git a/src/pages/guides/themes/oqtane-theme-solution-explained.md b/src/pages/guides/themes/oqtane-theme-solution-explained.md new file mode 100644 index 000000000..6637e1a30 --- /dev/null +++ b/src/pages/guides/themes/oqtane-theme-solution-explained.md @@ -0,0 +1,29 @@ +--- +uid: Guides..Themes.Index +--- + +# Themes - Theme Solution Explained + +A Oqtane Theme Solution is a Visual Studio project which is the basis for building a theme. + +It will typically contain the following in one or more projects: + +1. The basics such as the `ThemeInfo.cs`, the theme files and the container files. +1. A `wwwroot` folder with the CSS and JS files. +1. A `.nuspec` file to package the theme into a nuget package. +1. Code and specs to build / compile the result - such as `package.json` and `webpack.config.json`. +1. Code and specs to deploy the result - such as a `.nuspec` file. +1. An icon file, copyright information and more. + +In the example of the [Arsha theme]() +you can see that the theme solution contains two projects: + + + +  + +1. The first one is the theme and everything it consists of +1. The second one is the packaging project which separates nuget-creation into a separate project. + +> [!TIP] +> This separation of projects makes work easier, so we recommend you do the same. diff --git a/src/pages/guides/themes/parts-of-an-oqtane-theme.md b/src/pages/guides/themes/parts-of-an-oqtane-theme.md new file mode 100644 index 000000000..6c2d31f56 --- /dev/null +++ b/src/pages/guides/themes/parts-of-an-oqtane-theme.md @@ -0,0 +1,12 @@ +--- +uid: Guides..Themes.Index +--- + +# Themes Guide - Parts of a Theme + +Oqtane themes - when installed - consist of the following core parts: + +1. A DLL file that contains the compiled Blazor components. +2. JS and CSS files in `wwwroot/Themes/[your-theme-name]`. + + diff --git a/src/pages/guides/themes/parts.md b/src/pages/guides/themes/parts.md deleted file mode 100644 index 53d4f0728..000000000 --- a/src/pages/guides/themes/parts.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -uid: Guides..Themes.Index ---- - -# Themes Guide - Parts of a Theme - -Oqtane themes - when installed - consist of the following parts: - -1. A DLL file that contains the compiled Blazor components. -2. JS and CSS files in `wwwroot/Themes/[your-theme-name]`. - - - -## Theme Distribution and Installation - -Themes are usually distributed as nuget packages. -Internally such a nuget package is actually just a ZIP file. - - - -It contains: - -1. a `.nuspec` file containing information about it's contents -2. a `lib` folder containing the DLL file(s) -3. a `wwwroot` folder containing the JS and CSS files -4. an `icon.png` file -5. and some other files which are not important to us - - - -Theme installation works like any other module installation in Oqtane. -You can install a theme by either... - -1. uploading the nuget package in the Modules section of the admin area -2. by auto-downloading it from the Oqtane marketplace -3. by placing it in the `Packages` folder of your Oqtane installation -4. manually copying the files to your Oqtane installation - -...and then restarting Oqtane. - -## Code Structure of a Theme - -Internally a theme only needs the following 4 things: - -1. An own namespace such as `YourCompany.Themes.YourTheme`. -1. A `ThemeInfo.cs` file in that namespace which implements `Oqtane.Themes.ITheme`. - This file contains information about the theme like name, author, version, etc. -1. A theme file like `MyTheme.razor` which is the main thing shown to the user. -1. A container file like `Container.razor` which is the main wrapper around a module. - -> [!TIP] -> It is crucial that the namespace of the theme is unique, -> and that all these core elements (ThemeInfo, Theme, Container) -> are in _exactly_ this namespace. - diff --git a/src/pages/guides/themes/toc.yml b/src/pages/guides/themes/toc.yml new file mode 100644 index 000000000..9e332dd85 --- /dev/null +++ b/src/pages/guides/themes/toc.yml @@ -0,0 +1,15 @@ + +- name: Oqtane Themes Guide + href: index.md + +- name: Parts of an Oqtane Theme + href: parts-of-an-oqtane-theme.md + +- name: Distribution and Installation + href: oqtane-theme-distribution.md + +- name: Theme Code Explained + href: oqtane-theme-code-explained.md + +- name: Theme Solution Explained + href: oqtane-theme-solution-explained.md \ No newline at end of file diff --git a/src/pages/guides/toc.yml b/src/pages/guides/toc.yml index d26ea4285..a708d0ecc 100644 --- a/src/pages/guides/toc.yml +++ b/src/pages/guides/toc.yml @@ -7,9 +7,9 @@ topicHref: concepts/index.md - name: Themes - # href: themes/toc.yml - # topicHref: themes/index.md - href: themes/index.md + href: themes/toc.yml + topicHref: themes/index.md + # href: themes/index.md - name: Roadmap & History topicUid: Guides.Roadmap.Index