add theme creator module to simplify the scaffolding of external themes
This commit is contained in:
parent
d05747af1e
commit
1d3a79437c
186
Oqtane.Client/Modules/Admin/ThemeCreator/Index.razor
Normal file
186
Oqtane.Client/Modules/Admin/ThemeCreator/Index.razor
Normal file
|
@ -0,0 +1,186 @@
|
|||
@namespace Oqtane.Modules.Admin.ThemeCreator
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IThemeService ThemeService
|
||||
@inject IModuleService ModuleService
|
||||
@inject IPageModuleService PageModuleService
|
||||
@inject ISystemService SystemService
|
||||
@inject ISettingService SettingService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@using System.Text.RegularExpressions
|
||||
@using System.IO;
|
||||
|
||||
@if (string.IsNullOrEmpty(_themename) && _systeminfo != null && _templates != null)
|
||||
{
|
||||
<table class="table table-borderless">
|
||||
<tr>
|
||||
<td>
|
||||
<Label For="owner" HelpText="Enter the name of the organization who is developing this theme. It should not contain spaces or punctuation." ResourceKey="OwnerName">Owner Name: </Label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="owner" class="form-control" @bind="@_owner" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Label For="module" HelpText="Enter a name for this theme. It should not contain spaces or punctuation." ResourceKey="ThemeName">Theme Name: </Label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="module" class="form-control" @bind="@_theme" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Label For="template" HelpText="Select a theme template. Templates are located in the wwwroot/Themes/Templates folder on the server." ResourceKey="Template">Template: </Label>
|
||||
</td>
|
||||
<td>
|
||||
<select id="template" class="form-control" @onchange="(e => TemplateChanged(e))">
|
||||
<option value="-"><@Localizer["Select Template"]></option>
|
||||
@foreach (string template in _templates)
|
||||
{
|
||||
<option value="@template">@template</option>
|
||||
}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Label For="reference" HelpText="Select a framework reference version" ResourceKey="FrameworkReference">Framework Reference: </Label>
|
||||
</td>
|
||||
<td>
|
||||
<select id="reference" class="form-control" @bind="@_reference">
|
||||
@foreach (string version in Constants.ReleaseVersions.Split(','))
|
||||
{
|
||||
if (Version.Parse(version).CompareTo(Version.Parse("2.0.0")) >= 0)
|
||||
{
|
||||
<option value="@(version)">@(version)</option>
|
||||
}
|
||||
}
|
||||
<option value="local">@Localizer["Local Version"]</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
@if (!string.IsNullOrEmpty(_location))
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
<Label For="location" HelpText="Location where the theme will be created" ResourceKey="Location">Location: </Label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="module" class="form-control" @bind="@_location" readonly />
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
<button type="button" class="btn btn-success" @onclick="CreateTheme">@Localizer["Create Theme"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-success" @onclick="ActivateTheme">@Localizer["Activate Theme"]</button>
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _themename = string.Empty;
|
||||
private string _owner = string.Empty;
|
||||
private string _theme = string.Empty;
|
||||
private string _template = "-";
|
||||
private string _reference = Constants.Version;
|
||||
private string _location = string.Empty;
|
||||
|
||||
private Dictionary<string, string> _systeminfo;
|
||||
private List<string> _templates;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_themename = SettingService.GetSetting(ModuleState.Settings, "ThemeName", "");
|
||||
_systeminfo = await SystemService.GetSystemInfoAsync();
|
||||
_templates = await ThemeService.GetThemeTemplatesAsync();
|
||||
|
||||
if (string.IsNullOrEmpty(_themename))
|
||||
{
|
||||
AddModuleMessage(Localizer["Please Note That The Theme Creator Is Only Intended To Be Used In A Development Environment"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Once You Have Compiled The Theme And Restarted The Application You Can Activate The Theme Below"], MessageType.Info);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Theme Creator");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CreateTheme()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsValid(_owner) && IsValid(_theme) && _owner != _theme && _template != "-")
|
||||
{
|
||||
var theme = new Theme { Owner = _owner, Name = _theme, Template = _template, Version = _reference };
|
||||
theme = await ThemeService.CreateThemeAsync(theme);
|
||||
|
||||
var settings = ModuleState.Settings;
|
||||
SettingService.SetSetting(settings, "ThemeName", theme.ThemeName);
|
||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||
|
||||
GetLocation();
|
||||
|
||||
AddModuleMessage(Localizer["The Source Code For Your Theme Has Been Created At The Location Specified Below And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must <a href=\"{0}\">Restart</a> Your Application To Apply These Changes.", NavigateUrl("admin/system")], MessageType.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["You Must Provide A Valid Owner Name And Theme Name ( ie. No Punctuation Or Spaces And The Values Cannot Be The Same ) And Choose A Template"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Creating Theme");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ActivateTheme()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_themename))
|
||||
{
|
||||
await PageModuleService.DeletePageModuleAsync(ModuleState.PageModuleId);
|
||||
await ModuleService.DeleteModuleAsync(ModuleState.ModuleId);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Activating Theme");
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsValid(string name)
|
||||
{
|
||||
// must contain letters, underscores and digits and first character must be letter or underscore
|
||||
return !string.IsNullOrEmpty(name) && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
|
||||
}
|
||||
|
||||
private void TemplateChanged(ChangeEventArgs e)
|
||||
{
|
||||
_template = (string)e.Value;
|
||||
GetLocation();
|
||||
}
|
||||
|
||||
private void GetLocation()
|
||||
{
|
||||
_location = string.Empty;
|
||||
if (_template != "-" && _systeminfo != null && _systeminfo.ContainsKey("serverpath"))
|
||||
{
|
||||
string[] path = _systeminfo["serverpath"].Split(Path.DirectorySeparatorChar);
|
||||
_location = string.Join(Path.DirectorySeparatorChar, path, 0, path.Length - 2) +
|
||||
Path.DirectorySeparatorChar + _owner + "." + _theme;
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
15
Oqtane.Client/Modules/Admin/ThemeCreator/ModuleInfo.cs
Normal file
15
Oqtane.Client/Modules/Admin/ThemeCreator/ModuleInfo.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Modules.Admin.ThemeCreator
|
||||
{
|
||||
public class ModuleInfo : IModule
|
||||
{
|
||||
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
||||
{
|
||||
Name = "Theme Creator",
|
||||
Description = "Enables software developers to quickly create themes by automating many of the initial theme creation tasks",
|
||||
Version = "1.0.0",
|
||||
Categories = "Developer"
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using Oqtane.Models;
|
||||
using Oqtane.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -12,5 +12,7 @@ namespace Oqtane.Services
|
|||
List<ThemeControl> GetContainerControls(List<Theme> themes, string themeName);
|
||||
Task InstallThemesAsync();
|
||||
Task DeleteThemeAsync(string themeName);
|
||||
Task<Theme> CreateThemeAsync(Theme theme);
|
||||
Task<List<string>> GetThemeTemplatesAsync();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -50,5 +50,16 @@ namespace Oqtane.Services
|
|||
{
|
||||
await DeleteAsync($"{ApiUrl}/{themeName}");
|
||||
}
|
||||
|
||||
public async Task<Theme> CreateThemeAsync(Theme theme)
|
||||
{
|
||||
return await PostJsonAsync($"{ApiUrl}", theme);
|
||||
}
|
||||
|
||||
public async Task<List<string>> GetThemeTemplatesAsync()
|
||||
{
|
||||
List<string> templates = await GetJsonAsync<List<string>>($"{ApiUrl}/templates");
|
||||
return templates;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
83
Oqtane.Client/wwwroot/Themes/Siliqon.TestTheme/Theme.css
Normal file
83
Oqtane.Client/wwwroot/Themes/Siliqon.TestTheme/Theme.css
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* Oqtane Styles */
|
||||
|
||||
body {
|
||||
padding-top: 7rem;
|
||||
}
|
||||
|
||||
.controls {
|
||||
z-index: 2000;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.app-menu .nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.app-menu .nav-item a {
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.app-menu .nav-item a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.app-menu .nav-item a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.app-menu .nav-link .oi {
|
||||
width: 1.5rem;
|
||||
font-size: 1.1rem;
|
||||
vertical-align: text-top;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.navbar-toggler {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu {
|
||||
color:#ffffff;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
|
||||
.app-menu {
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.navbar {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.controls {
|
||||
height: 60px;
|
||||
top: 15px;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
background-color: rgb(0, 0, 0);
|
||||
}
|
||||
|
||||
.controls-group {
|
||||
float: right;
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
top: 60px;
|
||||
}
|
||||
}
|
|
@ -175,9 +175,9 @@ namespace Oqtane.Controllers
|
|||
// GET: api/<controller>/templates
|
||||
[HttpGet("templates")]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public List<string> Get()
|
||||
public List<string> GetTemplates()
|
||||
{
|
||||
var templates = new List<String>();
|
||||
var templates = new List<string>();
|
||||
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", Path.DirectorySeparatorChar.ToString());
|
||||
foreach (string directory in Directory.GetDirectories(templatePath))
|
||||
{
|
||||
|
@ -186,7 +186,7 @@ namespace Oqtane.Controllers
|
|||
return templates;
|
||||
}
|
||||
|
||||
// POST api/<controller>?moduleid=x
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public ModuleDefinition Post([FromBody] ModuleDefinition moduleDefinition)
|
||||
|
|
|
@ -103,5 +103,91 @@ namespace Oqtane.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
// GET: api/<controller>/templates
|
||||
[HttpGet("templates")]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public List<string> GetTemplates()
|
||||
{
|
||||
var templates = new List<string>();
|
||||
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Themes", "Templates", Path.DirectorySeparatorChar.ToString());
|
||||
foreach (string directory in Directory.GetDirectories(templatePath))
|
||||
{
|
||||
templates.Add(directory.Replace(templatePath, ""));
|
||||
}
|
||||
return templates;
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Roles = RoleNames.Host)]
|
||||
public Theme Post([FromBody] Theme theme)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
string rootPath;
|
||||
DirectoryInfo rootFolder = Directory.GetParent(_environment.ContentRootPath);
|
||||
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Themes", "Templates", theme.Template, Path.DirectorySeparatorChar.ToString());
|
||||
|
||||
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, theme.Owner + "." + theme.Name, Path.DirectorySeparatorChar.ToString());
|
||||
theme.ThemeName = theme.Owner + "." + theme.Name + ", " + theme.Owner + "." + theme.Name + ".Client.Oqtane";
|
||||
|
||||
ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, theme);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Theme Created {Theme}", theme);
|
||||
}
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
||||
private void ProcessTemplatesRecursively(DirectoryInfo current, string rootPath, string rootFolder, string templatePath, Theme theme)
|
||||
{
|
||||
// process folder
|
||||
string folderPath = Utilities.PathCombine(rootPath, current.FullName.Replace(templatePath, ""));
|
||||
folderPath = folderPath.Replace("[Owner]", theme.Owner);
|
||||
folderPath = folderPath.Replace("[Theme]", theme.Name);
|
||||
if (!Directory.Exists(folderPath))
|
||||
{
|
||||
Directory.CreateDirectory(folderPath);
|
||||
}
|
||||
|
||||
FileInfo[] files = current.GetFiles("*.*");
|
||||
if (files != null)
|
||||
{
|
||||
foreach (FileInfo file in files)
|
||||
{
|
||||
// process file
|
||||
string filePath = Path.Combine(folderPath, file.Name);
|
||||
filePath = filePath.Replace("[Owner]", theme.Owner);
|
||||
filePath = filePath.Replace("[Theme]", theme.Name);
|
||||
|
||||
string text = System.IO.File.ReadAllText(file.FullName);
|
||||
text = text.Replace("[Owner]", theme.Owner);
|
||||
text = text.Replace("[Theme]", theme.Name);
|
||||
text = text.Replace("[RootPath]", rootPath);
|
||||
text = text.Replace("[RootFolder]", rootFolder);
|
||||
text = text.Replace("[Folder]", folderPath);
|
||||
text = text.Replace("[File]", Path.GetFileName(filePath));
|
||||
if (theme.Version == "local")
|
||||
{
|
||||
text = text.Replace("[FrameworkVersion]", Constants.Version);
|
||||
text = text.Replace("[ClientReference]", "<Reference Include=\"Oqtane.Client\"><HintPath>..\\..\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Client.dll</HintPath></Reference>");
|
||||
text = text.Replace("[SharedReference]", "<Reference Include=\"Oqtane.Shared\"><HintPath>..\\..\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Shared.dll</HintPath></Reference>");
|
||||
}
|
||||
else
|
||||
{
|
||||
text = text.Replace("[FrameworkVersion]", theme.Version);
|
||||
text = text.Replace("[ClientReference]", "<PackageReference Include=\"Oqtane.Client\" Version=\"" + theme.Version + "\" />");
|
||||
text = text.Replace("[SharedReference]", "<PackageReference Include=\"Oqtane.Shared\" Version=\"" + theme.Version + "\" />");
|
||||
}
|
||||
System.IO.File.WriteAllText(filePath, text);
|
||||
}
|
||||
|
||||
DirectoryInfo[] folders = current.GetDirectories();
|
||||
|
||||
foreach (DirectoryInfo folder in folders.Reverse())
|
||||
{
|
||||
ProcessTemplatesRecursively(folder, rootPath, rootFolder, templatePath, theme);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
4
Oqtane.Server/wwwroot/Themes/Templates/External/Client/AssemblyInfo.cs
vendored
Normal file
4
Oqtane.Server/wwwroot/Themes/Templates/External/Client/AssemblyInfo.cs
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
using System.Resources;
|
||||
using Microsoft.Extensions.Localization;
|
||||
|
||||
[assembly: RootNamespace("[Owner].[Theme].Client")]
|
20
Oqtane.Server/wwwroot/Themes/Templates/External/Client/Containers/Container1.razor
vendored
Normal file
20
Oqtane.Server/wwwroot/Themes/Templates/External/Client/Containers/Container1.razor
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
@namespace [Owner].[Theme]
|
||||
@inherits ContainerBase
|
||||
|
||||
<div class="container">
|
||||
<div class="row px-4">
|
||||
<div class="d-flex flex-nowrap">
|
||||
<ModuleActions /><h2><ModuleTitle /></h2>
|
||||
</div>
|
||||
<hr class="app-rule" />
|
||||
</div>
|
||||
<div class="row px-4">
|
||||
<div class="container">
|
||||
<ModuleInstance />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
public override string Name => "Container1";
|
||||
}
|
15
Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs
vendored
Normal file
15
Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
using Oqtane.Models;
|
||||
using Oqtane.Themes;
|
||||
|
||||
namespace [Owner].[Theme]
|
||||
{
|
||||
public class ThemeInfo : ITheme
|
||||
{
|
||||
public Theme Theme => new Theme
|
||||
{
|
||||
Name = "[Theme]",
|
||||
Version = "1.0.0"
|
||||
};
|
||||
|
||||
}
|
||||
}
|
107
Oqtane.Server/wwwroot/Themes/Templates/External/Client/Themes/Theme1.razor
vendored
Normal file
107
Oqtane.Server/wwwroot/Themes/Templates/External/Client/Themes/Theme1.razor
vendored
Normal file
|
@ -0,0 +1,107 @@
|
|||
@namespace [Owner].[Theme]
|
||||
@inherits ThemeBase
|
||||
|
||||
<main role="main">
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-primary fixed-top">
|
||||
<Logo /><Menu Orientation="Horizontal" />
|
||||
<div class="controls ml-md-auto">
|
||||
<div class="controls-group"><UserProfile /> <Login /> <ControlPanel /></div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<Pane Name="Content" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Pane Name="Top Full Width" />
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<Pane Name="Top 100%" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<Pane Name="Left 50%" />
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<Pane Name="Right 50%" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<Pane Name="Left 33%" />
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<Pane Name="Center 33%" />
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<Pane Name="Right 33%" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<Pane Name="Left Outer 25%" />
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<Pane Name="Left Inner 25%" />
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<Pane Name="Right Inner 25%" />
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<Pane Name="Right Outer 25%" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<Pane Name="Left 25%" />
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<Pane Name="Center 50%" />
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<Pane Name="Right 25%" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<Pane Name="Left Sidebar 66%" />
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<Pane Name="Right Sidebar 33%" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<Pane Name="Left Sidebar 33%" />
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<Pane Name="Right Sidebar 66%" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<Pane Name="Bottom 100%" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Pane Name="Bottom Full Width" />
|
||||
</main>
|
||||
|
||||
@code {
|
||||
public override string Name => "Theme1";
|
||||
|
||||
public override string Panes => "Content,Top Full Width,Top 100%,Left 50%,Right 50%,Left 33%,Center 33%,Right 33%,Left Outer 25%,Left Inner 25%,Right Inner 25%,Right Outer 25%,Left 25%,Center 50%,Right 25%,Left Sidebar 66%,Right Sidebar 33%,Left Sidebar 33%,Right Sidebar 66%,Bottom 100%,Bottom Full Width";
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css", Integrity = "sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://code.jquery.com/jquery-3.5.1.slim.min.js", Integrity = "sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js", Integrity = "sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo", CrossOrigin = "anonymous" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js", Integrity = "sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI", CrossOrigin = "anonymous" }
|
||||
};
|
||||
}
|
34
Oqtane.Server/wwwroot/Themes/Templates/External/Client/[Owner].[Theme].Client.csproj
vendored
Normal file
34
Oqtane.Server/wwwroot/Themes/Templates/External/Client/[Owner].[Theme].Client.csproj
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<RazorLangVersion>3.0</RazorLangVersion>
|
||||
<Version>1.0.0</Version>
|
||||
<Authors>[Owner]</Authors>
|
||||
<Company>[Owner]</Company>
|
||||
<Description>[Description]</Description>
|
||||
<Product>[Owner].[Theme]</Product>
|
||||
<Copyright>[Owner]</Copyright>
|
||||
<AssemblyName>[Owner].[Theme].Client.Oqtane</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="5.0.0" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
[ClientReference]
|
||||
[SharedReference]
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- there may be other elements here -->
|
||||
<BlazorWebAssemblyEnableLinking>false</BlazorWebAssemblyEnableLinking>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
21
Oqtane.Server/wwwroot/Themes/Templates/External/Client/_Imports.razor
vendored
Normal file
21
Oqtane.Server/wwwroot/Themes/Templates/External/Client/_Imports.razor
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
@using System
|
||||
@using System.Linq
|
||||
@using System.Collections.Generic
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.JSInterop
|
||||
|
||||
@using Oqtane.Models
|
||||
@using Oqtane.Modules
|
||||
@using Oqtane.Modules.Controls
|
||||
@using Oqtane.Providers
|
||||
@using Oqtane.Security
|
||||
@using Oqtane.Services
|
||||
@using Oqtane.Shared
|
||||
@using Oqtane.Themes
|
||||
@using Oqtane.Themes.Controls
|
||||
@using Oqtane.UI
|
||||
@using Oqtane.Enums
|
83
Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].[Theme]/Theme.css
vendored
Normal file
83
Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].[Theme]/Theme.css
vendored
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* Oqtane Styles */
|
||||
|
||||
body {
|
||||
padding-top: 7rem;
|
||||
}
|
||||
|
||||
.controls {
|
||||
z-index: 2000;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.app-menu .nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.app-menu .nav-item a {
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.app-menu .nav-item a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.app-menu .nav-item a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.app-menu .nav-link .oi {
|
||||
width: 1.5rem;
|
||||
font-size: 1.1rem;
|
||||
vertical-align: text-top;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.navbar-toggler {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu {
|
||||
color:#ffffff;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
|
||||
.app-menu {
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.navbar {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.controls {
|
||||
height: 60px;
|
||||
top: 15px;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
background-color: rgb(0, 0, 0);
|
||||
}
|
||||
|
||||
.controls-group {
|
||||
float: right;
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
top: 60px;
|
||||
}
|
||||
}
|
17
Oqtane.Server/wwwroot/Themes/Templates/External/Package/[Owner].[Theme].Package.csproj
vendored
Normal file
17
Oqtane.Server/wwwroot/Themes/Templates/External/Package/[Owner].[Theme].Package.csproj
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Client\[Owner].[Theme].Client.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="IF $(ConfigurationName) == Debug (debug.cmd)" />
|
||||
<Exec Command="IF $(ConfigurationName) == Release (release.cmd)" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
27
Oqtane.Server/wwwroot/Themes/Templates/External/Package/[Owner].[Theme].nuspec
vendored
Normal file
27
Oqtane.Server/wwwroot/Themes/Templates/External/Package/[Owner].[Theme].nuspec
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>[Owner].[Theme]</id>
|
||||
<version>1.0.0</version>
|
||||
<authors>[Owner]</authors>
|
||||
<owners>[Owner]</owners>
|
||||
<title>[Theme]</title>
|
||||
<description>[Theme]</description>
|
||||
<copyright>[Owner]</copyright>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">MIT</license>
|
||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||
<iconUrl>https://www.oqtane.org/Portals/0/icon.jpg</iconUrl>
|
||||
<tags>oqtane module</tags>
|
||||
<releaseNotes></releaseNotes>
|
||||
<summary></summary>
|
||||
<dependencies>
|
||||
<dependency id="Oqtane.Framework" version="[FrameworkVersion]" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\Client\bin\Release\net5.0\[Owner].[Theme].Client.Oqtane.dll" target="lib\net5.0" />
|
||||
<file src="..\Client\bin\Release\net5.0\[Owner].[Theme].Client.Oqtane.pdb" target="lib\net5.0" />
|
||||
<file src="..\Client\wwwroot\**\*.*" target="wwwroot" />
|
||||
</files>
|
||||
</package>
|
3
Oqtane.Server/wwwroot/Themes/Templates/External/Package/debug.cmd
vendored
Normal file
3
Oqtane.Server/wwwroot/Themes/Templates/External/Package/debug.cmd
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
XCOPY "..\Client\bin\Debug\net5.0\[Owner].[Theme].Client.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net5.0\" /Y
|
||||
XCOPY "..\Client\bin\Debug\net5.0\[Owner].[Theme].Client.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net5.0\" /Y
|
||||
XCOPY "..\Client\wwwroot\*" "..\..\[RootFolder]\Oqtane.Client\wwwroot\" /Y /S /I
|
2
Oqtane.Server/wwwroot/Themes/Templates/External/Package/release.cmd
vendored
Normal file
2
Oqtane.Server/wwwroot/Themes/Templates/External/Package/release.cmd
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
"..\..\[RootFolder]\oqtane.package\nuget.exe" pack [Owner].[Theme].nuspec
|
||||
XCOPY "*.nupkg" "..\..\[RootFolder]\Oqtane.Server\wwwroot\Themes\" /Y
|
36
Oqtane.Server/wwwroot/Themes/Templates/External/[Owner].[Theme].sln
vendored
Normal file
36
Oqtane.Server/wwwroot/Themes/Templates/External/[Owner].[Theme].sln
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.28621.142
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "[Owner].[Theme].Client", "Client\[Owner].[Theme].Client.csproj", "{AA8E58A1-CD09-4208-BF66-A8BB341FD669}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "[Owner].[Theme].Package", "Package\[Owner].[Theme].Package.csproj", "{C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Wasm|Any CPU = Wasm|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Wasm|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Wasm|Any CPU.Build.0 = Release|Any CPU
|
||||
{C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Wasm|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Wasm|Any CPU.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1D016F15-46FE-4726-8DFD-2E4FD4DC7668}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Oqtane.Models
|
||||
|
@ -14,6 +14,7 @@ namespace Oqtane.Models
|
|||
Contact = "";
|
||||
License = "";
|
||||
Dependencies = "";
|
||||
Template = "";
|
||||
}
|
||||
|
||||
public string ThemeName { get; set; }
|
||||
|
@ -28,6 +29,7 @@ namespace Oqtane.Models
|
|||
public List<ThemeControl> Themes { get; set; }
|
||||
public List<ThemeControl> Layouts { get; set; }
|
||||
public List<ThemeControl> Containers { get; set; }
|
||||
public string Template { get; set; }
|
||||
|
||||
//[Obsolete("This property is obsolete. Use Themes instead.", false)]
|
||||
public string ThemeControls { get; set; }
|
||||
|
|
Loading…
Reference in New Issue
Block a user