Many updates
This commit is contained in:
parent
a02b607bc6
commit
87754c8e06
@ -1,16 +0,0 @@
|
|||||||
@page "/counter"
|
|
||||||
|
|
||||||
<h1>Counter</h1>
|
|
||||||
|
|
||||||
<p>Current count: @currentCount</p>
|
|
||||||
|
|
||||||
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private int currentCount = 0;
|
|
||||||
|
|
||||||
private void IncrementCount()
|
|
||||||
{
|
|
||||||
currentCount++;
|
|
||||||
}
|
|
||||||
}
|
|
7
Seenginx/Pages/Dmesg.razor
Normal file
7
Seenginx/Pages/Dmesg.razor
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@page "/dmesg"
|
||||||
|
|
||||||
|
<h3>Dmesg</h3>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
}
|
@ -1,46 +0,0 @@
|
|||||||
@page "/fetchdata"
|
|
||||||
|
|
||||||
@using Seenginx.Data
|
|
||||||
@inject WeatherForecastService ForecastService
|
|
||||||
|
|
||||||
<h1>Weather forecast</h1>
|
|
||||||
|
|
||||||
<p>This component demonstrates fetching data from a service.</p>
|
|
||||||
|
|
||||||
@if (forecasts == null)
|
|
||||||
{
|
|
||||||
<p><em>Loading...</em></p>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Date</th>
|
|
||||||
<th>Temp. (C)</th>
|
|
||||||
<th>Temp. (F)</th>
|
|
||||||
<th>Summary</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach (var forecast in forecasts)
|
|
||||||
{
|
|
||||||
<tr>
|
|
||||||
<td>@forecast.Date.ToShortDateString()</td>
|
|
||||||
<td>@forecast.TemperatureC</td>
|
|
||||||
<td>@forecast.TemperatureF</td>
|
|
||||||
<td>@forecast.Summary</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
}
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private WeatherForecast[] forecasts;
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
|
|
||||||
}
|
|
||||||
}
|
|
7
Seenginx/Pages/Nginx.razor
Normal file
7
Seenginx/Pages/Nginx.razor
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@page "/nginx"
|
||||||
|
|
||||||
|
<h3>Nginx</h3>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
}
|
7
Seenginx/Pages/Systemd.razor
Normal file
7
Seenginx/Pages/Systemd.razor
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@page "/systemd"
|
||||||
|
|
||||||
|
<h3>SystemD</h3>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
}
|
@ -13,15 +13,17 @@
|
|||||||
<link rel="icon" href="~/favicon.png" />
|
<link rel="icon" href="~/favicon.png" />
|
||||||
<title>Seenginx</title>
|
<title>Seenginx</title>
|
||||||
<base href="~/" />
|
<base href="~/" />
|
||||||
|
<link rel="stylesheet" href="~/css/side-menu.css" asp-append-version="true" />
|
||||||
<environment include="Staging,Production">
|
<environment include="Staging,Production">
|
||||||
<link rel="stylesheet" href="~/css/open-iconic.min.css" />
|
<link rel="stylesheet" href="~/css/open-iconic.min.css" asp-append-version="true" />
|
||||||
<link rel="stylesheet" href="~/css/pure.min.css" />
|
<link rel="stylesheet" href="~/css/pure.min.css" asp-append-version="true" />
|
||||||
|
<link rel="stylesheet" href="~/css/main.min.css" asp-append-version="true" />
|
||||||
</environment>
|
</environment>
|
||||||
<environment include="Development">
|
<environment include="Development">
|
||||||
<link rel="stylesheet" href="~/css/open-iconic.css" />
|
<link rel="stylesheet" href="~/css/open-iconic.css" asp-append-version="true" />
|
||||||
<link rel="stylesheet" href="~/css/pure.css" />
|
<link rel="stylesheet" href="~/css/pure.css" asp-append-version="true" />
|
||||||
|
<link rel="stylesheet" href="~/css/main.css" asp-append-version="true" />
|
||||||
</environment>
|
</environment>
|
||||||
<link href="css/site.css" rel="stylesheet" />
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<app>
|
<app>
|
||||||
@ -40,5 +42,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="_framework/blazor.server.js"></script>
|
<script src="_framework/blazor.server.js"></script>
|
||||||
|
<script src="js/modal.js" asp-append-version="true"></script>
|
||||||
|
<script src="js/ui.js" asp-append-version="true"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
26
Seenginx/SCSS/base.scss
Normal file
26
Seenginx/SCSS/base.scss
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
body {
|
||||||
|
box-sizing: border-box
|
||||||
|
}
|
||||||
|
|
||||||
|
*, ::before, ::after {
|
||||||
|
box-sizing: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
#blazor-error-ui {
|
||||||
|
background: lightyellow;
|
||||||
|
bottom: 0;
|
||||||
|
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||||
|
display: none;
|
||||||
|
left: 0;
|
||||||
|
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 1000;
|
||||||
|
|
||||||
|
& .dismiss {
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
right: 0.75rem;
|
||||||
|
top: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
4
Seenginx/SCSS/main.scss
Normal file
4
Seenginx/SCSS/main.scss
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
@import "mixins.scss";
|
||||||
|
@import "base.scss";
|
||||||
|
@import "utility.scss";
|
||||||
|
@import "side-menu.scss";
|
58
Seenginx/SCSS/mixins.scss
Normal file
58
Seenginx/SCSS/mixins.scss
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
//MEDIA QUERY MANAGER
|
||||||
|
|
||||||
|
/*$breakpoint argument choices:
|
||||||
|
- phone
|
||||||
|
- tab-port
|
||||||
|
- tab-land
|
||||||
|
- desk
|
||||||
|
- big-desktop
|
||||||
|
*/
|
||||||
|
|
||||||
|
@mixin MediaQuery($breakpoint) {
|
||||||
|
// max-width:600px;
|
||||||
|
@if $breakpoint==phone {
|
||||||
|
@media only screen and (max-width: 37.5em) {
|
||||||
|
@content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@if $breakpoint==tab-p {
|
||||||
|
// min-width:601px;
|
||||||
|
// max-width:900px;
|
||||||
|
@media only screen and (min-width: 601px) and (max-width: 900px) {
|
||||||
|
@content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@if $breakpoint==tab-l {
|
||||||
|
// min-width:901px;
|
||||||
|
// max-width:1200px;
|
||||||
|
@media only screen and (min-width: 901px) and (max-width: 1200px) {
|
||||||
|
@content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@if $breakpoint==laptop {
|
||||||
|
// min-width:1201px;
|
||||||
|
// max-width:1366px;
|
||||||
|
@media only screen and (min-width: 1201px) and (max-width: 1366px) {
|
||||||
|
@content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@if $breakpoint==desk {
|
||||||
|
// min-width:1201px;
|
||||||
|
// max-width:1800px;
|
||||||
|
@media only screen and (min-width: 1201px) and (max-width: 1800px) {
|
||||||
|
@content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@if $breakpoint==big-d {
|
||||||
|
// min-width:1801px;
|
||||||
|
// max-width:4000px;
|
||||||
|
@media only screen and (min-width: 1801px) and (max-width: 4000px) {
|
||||||
|
@content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
182
Seenginx/SCSS/side-menu.scss
Normal file
182
Seenginx/SCSS/side-menu.scss
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
body {
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--leftPanel: 150px;
|
||||||
|
--negativeLeftPanel: -150px;
|
||||||
|
--mobileLeftPanel: 150px;
|
||||||
|
--mobileNegativeLeftPanel: -150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pure-img-responsive {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add transition to containers so they can push in and out.
|
||||||
|
*/
|
||||||
|
#layout,
|
||||||
|
#menu,
|
||||||
|
.menu-link {
|
||||||
|
-webkit-transition: all 0.2s ease-out;
|
||||||
|
-moz-transition: all 0.2s ease-out;
|
||||||
|
-ms-transition: all 0.2s ease-out;
|
||||||
|
-o-transition: all 0.2s ease-out;
|
||||||
|
transition: all 0.2s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is the parent `<div>` that contains the menu and the content area.
|
||||||
|
*/
|
||||||
|
#layout {
|
||||||
|
position: relative;
|
||||||
|
left: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
|
||||||
|
& .menu-link {
|
||||||
|
left: var(--leftPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
& #menu {
|
||||||
|
left: var(--leftPanel);
|
||||||
|
width: var(--leftPanel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The `#menu` `<div>` is the parent `<div>` that contains the `.pure-menu` that
|
||||||
|
appears on the left side of the page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#menu {
|
||||||
|
margin-left: var(--negativeLeftPanel); /* "#menu" width */
|
||||||
|
width: var(--leftPanel);
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 1000; /* so the menu or its navicon stays above all content */
|
||||||
|
background: #191818;
|
||||||
|
overflow-y: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
//All anchors inside the menu should be styled like this.
|
||||||
|
& a {
|
||||||
|
color: #999;
|
||||||
|
border: none;
|
||||||
|
padding: 0.6em 0 0.6em 0.6em;
|
||||||
|
}
|
||||||
|
//Remove all background/borders, since we are applying them to #menu.
|
||||||
|
& .pure-menu,
|
||||||
|
& .pure-menu ul {
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
//Add that light border to separate items into groups.
|
||||||
|
& .pure-menu ul,
|
||||||
|
& .pure-menu .menu-item-divided {
|
||||||
|
border-top: 1px solid #333;
|
||||||
|
}
|
||||||
|
//Change color of the anchor links on hover/focus.
|
||||||
|
& .pure-menu li a:hover,
|
||||||
|
& .pure-menu li a:focus {
|
||||||
|
background: #333;
|
||||||
|
}
|
||||||
|
//This styles the selected menu item `<li>`.
|
||||||
|
& .pure-menu-selected,
|
||||||
|
& .pure-menu-heading {
|
||||||
|
background: #1f8dd6;
|
||||||
|
}
|
||||||
|
//This styles a link within a selected menu item `<li>`.
|
||||||
|
& .pure-menu-selected a {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
//This styles the menu heading.
|
||||||
|
& .pure-menu-heading {
|
||||||
|
font-size: 110%;
|
||||||
|
color: #fff;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Dynamic Button For Responsive Menu -------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
The button to open/close the Menu is custom-made and not part of Pure. Here's
|
||||||
|
how it works:
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
`.menu-link` represents the responsive menu toggle that shows/hides on
|
||||||
|
small screens.
|
||||||
|
*/
|
||||||
|
.menu-link {
|
||||||
|
position: fixed;
|
||||||
|
display: block; /* show this only on small screens */
|
||||||
|
top: 0;
|
||||||
|
left: 0; /* "#menu width" */
|
||||||
|
background: #000;
|
||||||
|
background: rgba(0,0,0,0.7);
|
||||||
|
font-size: 16px; /* change this value to increase/decrease button size */
|
||||||
|
z-index: 10;
|
||||||
|
width: min-content;
|
||||||
|
height: auto;
|
||||||
|
padding: 14px;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* -- Responsive Styles (Media Queries) ------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Hides the menu at `48em`, but modify this based on your app's needs.
|
||||||
|
*/
|
||||||
|
@media (min-width: 48em) {
|
||||||
|
|
||||||
|
.header,
|
||||||
|
.content {
|
||||||
|
padding-left: 2em;
|
||||||
|
padding-right: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layout {
|
||||||
|
padding-left: var(--leftPanel); /* left col width "#menu" */
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu {
|
||||||
|
left: var(--leftPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-link {
|
||||||
|
position: fixed;
|
||||||
|
left: var(--leftPanel);
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layout.active .menu-link {
|
||||||
|
left: var(--leftPanel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 48em) {
|
||||||
|
/* Only apply this when the window is small. Otherwise, the following
|
||||||
|
case results in extra padding on the left:
|
||||||
|
* Make the window small.
|
||||||
|
* Tap the menu to trigger the active state.
|
||||||
|
* Make the window large again.
|
||||||
|
*/
|
||||||
|
#layout.active {
|
||||||
|
position: relative;
|
||||||
|
left: var(--leftPanel);
|
||||||
|
}
|
||||||
|
}
|
9
Seenginx/SCSS/utility.scss
Normal file
9
Seenginx/SCSS/utility.scss
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.isHidden {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
&Mobile {
|
||||||
|
@include MediaQuery(phone) {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,8 +5,28 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="wwwroot\fonts\" />
|
<Content Remove="compilerconfig.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="SCSS\side-menu.scss" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
<Folder Include="wwwroot\images\" />
|
<Folder Include="wwwroot\images\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="compilerconfig.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.3" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Seenginx.Models\Seenginx.Models.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
<div class="sidebar">
|
<div id="layout" class="@MenuActiveClass">
|
||||||
<NavMenu />
|
|
||||||
|
<NavMenu @bind-MenuActiveClass="MenuActiveClass" />
|
||||||
|
|
||||||
|
<div id="main">
|
||||||
|
@Body
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="main">
|
@code{
|
||||||
<div class="top-row px-4">
|
public string MenuActiveClass { get; set; } = null;
|
||||||
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
|
}
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content px-4">
|
|
||||||
@Body
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,37 +1,36 @@
|
|||||||
<div class="top-row pl-4 navbar navbar-dark">
|
@inherits NavMenuBase
|
||||||
<a class="navbar-brand" href="">Seenginx</a>
|
|
||||||
<button class="navbar-toggler" @onclick="ToggleNavMenu">
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
|
<a href="#menu" id="menuLink" class="menu-link @MenuActiveClass" @onclick="ToggleMenu">
|
||||||
<ul class="nav flex-column">
|
<span class="oi" data-glyph="menu"></span>
|
||||||
<li class="nav-item px-3">
|
</a>
|
||||||
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
|
|
||||||
<span class="oi oi-home" aria-hidden="true"></span> Home
|
|
||||||
</NavLink>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item px-3">
|
|
||||||
<NavLink class="nav-link" href="counter">
|
|
||||||
<span class="oi oi-plus" aria-hidden="true"></span> Counter
|
|
||||||
</NavLink>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item px-3">
|
|
||||||
<NavLink class="nav-link" href="fetchdata">
|
|
||||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
|
|
||||||
</NavLink>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@code {
|
<div id="menu" class="@MenuActiveClass">
|
||||||
private bool collapseNavMenu = true;
|
<div class="pure-menu">
|
||||||
|
<NavLink class="pure-menu-heading" href="/" Match="NavLinkMatch.All">
|
||||||
|
<span class="oi" data-glyph="bolt"></span>
|
||||||
|
<span class="isHiddenMobile">Seenginx</span>
|
||||||
|
</NavLink>
|
||||||
|
|
||||||
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
|
<ul class="pure-menu-list">
|
||||||
|
<li class="pure-menu-item @ActiveNav.GetValueOrDefault("nginx")">
|
||||||
|
<NavLink href="/nginx" class="pure-menu-link" @onclick="@(e => SelectMenuItem("nginx"))">
|
||||||
|
<span class="oi" data-glyph="code"></span>
|
||||||
|
<span class="isHiddenMobile">NGINX</span>
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
<li class="pure-menu-item @ActiveNav.GetValueOrDefault("systemd")">
|
||||||
|
<NavLink href="/systemd" class="pure-menu-link" @onclick="@(e => SelectMenuItem("systemd"))">
|
||||||
|
<span class="oi" data-glyph="cog"></span>
|
||||||
|
<span class="isHiddenMobile">SystemD</span>
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
|
||||||
private void ToggleNavMenu()
|
<li class="pure-menu-item @ActiveNav.GetValueOrDefault("dmesg")">
|
||||||
{
|
<NavLink href="/dmesg" class="pure-menu-link" @onclick="@(e => SelectMenuItem("dmesg"))">
|
||||||
collapseNavMenu = !collapseNavMenu;
|
<span class="oi" data-glyph="dashboard"></span>
|
||||||
}
|
<span class="isHiddenMobile">Dmesg</span>
|
||||||
}
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
47
Seenginx/Shared/NavMenu.razor.cs
Normal file
47
Seenginx/Shared/NavMenu.razor.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Seenginx.Shared
|
||||||
|
{
|
||||||
|
public class NavMenuBase : ComponentBase
|
||||||
|
{
|
||||||
|
protected Dictionary<string, string> ActiveNav { get; set; }
|
||||||
|
public bool CollapsePanel { get; set; } = false;
|
||||||
|
[Parameter]
|
||||||
|
public string MenuActiveClass { get; set; }
|
||||||
|
|
||||||
|
[ParameterAttribute]
|
||||||
|
public EventCallback<string> MenuActiveClassChanged { get; set; }
|
||||||
|
|
||||||
|
protected async override Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
ActiveNav = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "nginx", null },
|
||||||
|
{ "systemd", null },
|
||||||
|
{ "dmesg", null }
|
||||||
|
};
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SelectMenuItem(string menuItem)
|
||||||
|
{
|
||||||
|
foreach (var key in ActiveNav.Keys.ToArray())
|
||||||
|
ActiveNav[key] = null;
|
||||||
|
|
||||||
|
ActiveNav[menuItem] = "pure-menu-selected";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task ToggleMenu()
|
||||||
|
{
|
||||||
|
CollapsePanel = !CollapsePanel;
|
||||||
|
MenuActiveClass = CollapsePanel ? "active" : null;
|
||||||
|
|
||||||
|
await MenuActiveClassChanged.InvokeAsync(MenuActiveClass);
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Hosting;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Seenginx.Data;
|
|
||||||
using Seenginx.Services;
|
using Seenginx.Services;
|
||||||
|
|
||||||
namespace Seenginx
|
namespace Seenginx
|
||||||
@ -26,11 +25,15 @@ namespace Seenginx
|
|||||||
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddRazorPages();
|
services.AddRazorPages()
|
||||||
|
#if DEBUG
|
||||||
|
.AddRazorRuntimeCompilation()
|
||||||
|
#endif
|
||||||
|
;
|
||||||
services.AddServerSideBlazor();
|
services.AddServerSideBlazor();
|
||||||
services.AddTransient<IDmesgService,DmesgService>();
|
services.AddTransient<IDmesgService, DmesgService>();
|
||||||
services.AddTransient<INginxService,NginxService>();
|
services.AddTransient<INginxService, NginxService>();
|
||||||
services.AddTransient<ISystemDService,SystemDService>();
|
services.AddTransient<ISystemDService, SystemDService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
6
Seenginx/compilerconfig.json
Normal file
6
Seenginx/compilerconfig.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"outputFile": "wwwroot/css/main.css",
|
||||||
|
"inputFile": "SCSS/main.scss"
|
||||||
|
}
|
||||||
|
]
|
63
Seenginx/compilerconfig.json.defaults
Normal file
63
Seenginx/compilerconfig.json.defaults
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"compilers": {
|
||||||
|
"less": {
|
||||||
|
"autoPrefix": "",
|
||||||
|
"cssComb": "none",
|
||||||
|
"ieCompat": true,
|
||||||
|
"strictMath": false,
|
||||||
|
"strictUnits": false,
|
||||||
|
"relativeUrls": true,
|
||||||
|
"rootPath": "",
|
||||||
|
"sourceMapRoot": "",
|
||||||
|
"sourceMapBasePath": "",
|
||||||
|
"sourceMap": false
|
||||||
|
},
|
||||||
|
"sass": {
|
||||||
|
"autoPrefix": "",
|
||||||
|
"includePath": "",
|
||||||
|
"indentType": "space",
|
||||||
|
"indentWidth": 2,
|
||||||
|
"outputStyle": "nested",
|
||||||
|
"Precision": 5,
|
||||||
|
"relativeUrls": true,
|
||||||
|
"sourceMapRoot": "",
|
||||||
|
"lineFeed": "",
|
||||||
|
"sourceMap": false
|
||||||
|
},
|
||||||
|
"stylus": {
|
||||||
|
"sourceMap": false
|
||||||
|
},
|
||||||
|
"babel": {
|
||||||
|
"sourceMap": false
|
||||||
|
},
|
||||||
|
"coffeescript": {
|
||||||
|
"bare": false,
|
||||||
|
"runtimeMode": "node",
|
||||||
|
"sourceMap": false
|
||||||
|
},
|
||||||
|
"handlebars": {
|
||||||
|
"root": "",
|
||||||
|
"noBOM": false,
|
||||||
|
"name": "",
|
||||||
|
"namespace": "",
|
||||||
|
"knownHelpersOnly": false,
|
||||||
|
"forcePartial": false,
|
||||||
|
"knownHelpers": [],
|
||||||
|
"commonjs": "",
|
||||||
|
"amd": false,
|
||||||
|
"sourceMap": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minifiers": {
|
||||||
|
"css": {
|
||||||
|
"enabled": true,
|
||||||
|
"termSemicolons": true,
|
||||||
|
"gzip": false
|
||||||
|
},
|
||||||
|
"javascript": {
|
||||||
|
"enabled": true,
|
||||||
|
"termSemicolons": true,
|
||||||
|
"gzip": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
173
Seenginx/wwwroot/css/main.css
Normal file
173
Seenginx/wwwroot/css/main.css
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
/*$breakpoint argument choices:
|
||||||
|
- phone
|
||||||
|
- tab-port
|
||||||
|
- tab-land
|
||||||
|
- desk
|
||||||
|
- big-desktop
|
||||||
|
*/
|
||||||
|
body {
|
||||||
|
box-sizing: border-box; }
|
||||||
|
|
||||||
|
*, ::before, ::after {
|
||||||
|
box-sizing: inherit; }
|
||||||
|
|
||||||
|
#blazor-error-ui {
|
||||||
|
background: lightyellow;
|
||||||
|
bottom: 0;
|
||||||
|
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||||
|
display: none;
|
||||||
|
left: 0;
|
||||||
|
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 1000; }
|
||||||
|
#blazor-error-ui .dismiss {
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
right: 0.75rem;
|
||||||
|
top: 0.5rem; }
|
||||||
|
|
||||||
|
.isHidden {
|
||||||
|
display: none; }
|
||||||
|
@media only screen and (max-width: 37.5em) {
|
||||||
|
.isHiddenMobile {
|
||||||
|
display: none; } }
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: #777; }
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--leftPanel: 150px;
|
||||||
|
--negativeLeftPanel: -150px;
|
||||||
|
--mobileLeftPanel: 150px;
|
||||||
|
--mobileNegativeLeftPanel: -150px; }
|
||||||
|
|
||||||
|
.pure-img-responsive {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add transition to containers so they can push in and out.
|
||||||
|
*/
|
||||||
|
#layout,
|
||||||
|
#menu,
|
||||||
|
.menu-link {
|
||||||
|
-webkit-transition: all 0.2s ease-out;
|
||||||
|
-moz-transition: all 0.2s ease-out;
|
||||||
|
-ms-transition: all 0.2s ease-out;
|
||||||
|
-o-transition: all 0.2s ease-out;
|
||||||
|
transition: all 0.2s ease-out; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is the parent `<div>` that contains the menu and the content area.
|
||||||
|
*/
|
||||||
|
#layout {
|
||||||
|
position: relative;
|
||||||
|
left: 0;
|
||||||
|
padding-left: 0; }
|
||||||
|
#layout.active .menu-link {
|
||||||
|
left: var(--leftPanel); }
|
||||||
|
#layout.active #menu {
|
||||||
|
left: var(--leftPanel);
|
||||||
|
width: var(--leftPanel); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
The `#menu` `<div>` is the parent `<div>` that contains the `.pure-menu` that
|
||||||
|
appears on the left side of the page.
|
||||||
|
*/
|
||||||
|
#menu {
|
||||||
|
margin-left: var(--negativeLeftPanel);
|
||||||
|
/* "#menu" width */
|
||||||
|
width: var(--leftPanel);
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
/* so the menu or its navicon stays above all content */
|
||||||
|
background: #191818;
|
||||||
|
overflow-y: auto;
|
||||||
|
-webkit-overflow-scrolling: touch; }
|
||||||
|
#menu a {
|
||||||
|
color: #999;
|
||||||
|
border: none;
|
||||||
|
padding: 0.6em 0 0.6em 0.6em; }
|
||||||
|
#menu .pure-menu,
|
||||||
|
#menu .pure-menu ul {
|
||||||
|
border: none;
|
||||||
|
background: transparent; }
|
||||||
|
#menu .pure-menu ul,
|
||||||
|
#menu .pure-menu .menu-item-divided {
|
||||||
|
border-top: 1px solid #333; }
|
||||||
|
#menu .pure-menu li a:hover,
|
||||||
|
#menu .pure-menu li a:focus {
|
||||||
|
background: #333; }
|
||||||
|
#menu .pure-menu-selected,
|
||||||
|
#menu .pure-menu-heading {
|
||||||
|
background: #1f8dd6; }
|
||||||
|
#menu .pure-menu-selected a {
|
||||||
|
color: #fff; }
|
||||||
|
#menu .pure-menu-heading {
|
||||||
|
font-size: 110%;
|
||||||
|
color: #fff;
|
||||||
|
margin: 0; }
|
||||||
|
|
||||||
|
/* -- Dynamic Button For Responsive Menu -------------------------------------*/
|
||||||
|
/*
|
||||||
|
The button to open/close the Menu is custom-made and not part of Pure. Here's
|
||||||
|
how it works:
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
`.menu-link` represents the responsive menu toggle that shows/hides on
|
||||||
|
small screens.
|
||||||
|
*/
|
||||||
|
.menu-link {
|
||||||
|
position: fixed;
|
||||||
|
display: block;
|
||||||
|
/* show this only on small screens */
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
/* "#menu width" */
|
||||||
|
background: #000;
|
||||||
|
background: rgba(0, 0, 0, 0.7);
|
||||||
|
font-size: 16px;
|
||||||
|
/* change this value to increase/decrease button size */
|
||||||
|
z-index: 10;
|
||||||
|
width: min-content;
|
||||||
|
height: auto;
|
||||||
|
padding: 14px; }
|
||||||
|
.menu-link:hover, .menu-link:focus {
|
||||||
|
background: #000; }
|
||||||
|
|
||||||
|
/* -- Responsive Styles (Media Queries) ------------------------------------- */
|
||||||
|
/*
|
||||||
|
Hides the menu at `48em`, but modify this based on your app's needs.
|
||||||
|
*/
|
||||||
|
@media (min-width: 48em) {
|
||||||
|
.header,
|
||||||
|
.content {
|
||||||
|
padding-left: 2em;
|
||||||
|
padding-right: 2em; }
|
||||||
|
#layout {
|
||||||
|
padding-left: var(--leftPanel);
|
||||||
|
/* left col width "#menu" */
|
||||||
|
left: 0; }
|
||||||
|
#menu {
|
||||||
|
left: var(--leftPanel); }
|
||||||
|
.menu-link {
|
||||||
|
position: fixed;
|
||||||
|
left: var(--leftPanel);
|
||||||
|
display: none; }
|
||||||
|
#layout.active .menu-link {
|
||||||
|
left: var(--leftPanel); } }
|
||||||
|
|
||||||
|
@media (max-width: 48em) {
|
||||||
|
/* Only apply this when the window is small. Otherwise, the following
|
||||||
|
case results in extra padding on the left:
|
||||||
|
* Make the window small.
|
||||||
|
* Tap the menu to trigger the active state.
|
||||||
|
* Make the window large again.
|
||||||
|
*/
|
||||||
|
#layout.active {
|
||||||
|
position: relative;
|
||||||
|
left: var(--leftPanel); } }
|
1
Seenginx/wwwroot/css/main.min.css
vendored
Normal file
1
Seenginx/wwwroot/css/main.min.css
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
body{box-sizing:border-box;}*,::before,::after{box-sizing:inherit;}#blazor-error-ui{background:#ffffe0;bottom:0;box-shadow:0 -1px 2px rgba(0,0,0,.2);display:none;left:0;padding:.6rem 1.25rem .7rem 1.25rem;position:fixed;width:100%;z-index:1000;}#blazor-error-ui .dismiss{cursor:pointer;position:absolute;right:.75rem;top:.5rem;}.isHidden{display:none;}@media only screen and (max-width:37.5em){.isHiddenMobile{display:none;}}body{color:#777;}:root{--leftPanel:150px;--negativeLeftPanel:-150px;--mobileLeftPanel:150px;--mobileNegativeLeftPanel:-150px;}.pure-img-responsive{max-width:100%;height:auto;}#layout,#menu,.menu-link{-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-ms-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out;}#layout{position:relative;left:0;padding-left:0;}#layout.active .menu-link{left:var(--leftPanel);}#layout.active #menu{left:var(--leftPanel);width:var(--leftPanel);}#menu{margin-left:var(--negativeLeftPanel);width:var(--leftPanel);position:fixed;top:0;left:0;bottom:0;z-index:1000;background:#191818;overflow-y:auto;-webkit-overflow-scrolling:touch;}#menu a{color:#999;border:none;padding:.6em 0 .6em .6em;}#menu .pure-menu,#menu .pure-menu ul{border:none;background:transparent;}#menu .pure-menu ul,#menu .pure-menu .menu-item-divided{border-top:1px solid #333;}#menu .pure-menu li a:hover,#menu .pure-menu li a:focus{background:#333;}#menu .pure-menu-selected,#menu .pure-menu-heading{background:#1f8dd6;}#menu .pure-menu-selected a{color:#fff;}#menu .pure-menu-heading{font-size:110%;color:#fff;margin:0;}.menu-link{position:fixed;display:block;top:0;left:0;background:#000;background:rgba(0,0,0,.7);font-size:16px;z-index:10;width:min-content;height:auto;padding:14px;}.menu-link:hover,.menu-link:focus{background:#000;}@media(min-width:48em){.header,.content{padding-left:2em;padding-right:2em;}#layout{padding-left:var(--leftPanel);left:0;}#menu{left:var(--leftPanel);}.menu-link{position:fixed;left:var(--leftPanel);display:none;}#layout.active .menu-link{left:var(--leftPanel);}}@media(max-width:48em){#layout.active{position:relative;left:var(--leftPanel);}}
|
@ -1,7 +0,0 @@
|
|||||||
body {
|
|
||||||
box-sizing: border-box
|
|
||||||
}
|
|
||||||
|
|
||||||
*, ::before, ::after {
|
|
||||||
box-sizing: inherit
|
|
||||||
}
|
|
540
Seenginx/wwwroot/js/modal.js
Normal file
540
Seenginx/wwwroot/js/modal.js
Normal file
@ -0,0 +1,540 @@
|
|||||||
|
/*!
|
||||||
|
* CSS Modal
|
||||||
|
* http://drublic.github.com/css-modal
|
||||||
|
*
|
||||||
|
* @author Hans Christian Reinl - @drublic
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function (global, $) {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Storage for functions and attributes
|
||||||
|
*/
|
||||||
|
var modal = {
|
||||||
|
|
||||||
|
activeElement: undefined, // Store for currently active element
|
||||||
|
lastActive: undefined, // Store for last active elemet
|
||||||
|
stackedElements: [], // Store for stacked elements
|
||||||
|
|
||||||
|
// All elements that can get focus, can be tabbed in a modal
|
||||||
|
tabbableElements: 'a[href], area[href], input:not([disabled]),' +
|
||||||
|
'select:not([disabled]), textarea:not([disabled]),' +
|
||||||
|
'button:not([disabled]), iframe, object, embed, *[tabindex],' +
|
||||||
|
'*[contenteditable]',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Polyfill addEventListener for IE8 (only very basic)
|
||||||
|
* @param event {string} event type
|
||||||
|
* @param element {Node} node to fire event on
|
||||||
|
* @param callback {function} gets fired if event is triggered
|
||||||
|
*/
|
||||||
|
on: function (event, elements, callback) {
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
if (typeof event !== 'string') {
|
||||||
|
throw new Error('Type error: `event` has to be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof callback !== 'function') {
|
||||||
|
throw new Error('Type error: `callback` has to be a function');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!elements) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make elements an array and attach event listeners
|
||||||
|
if (!elements.length) {
|
||||||
|
elements = [elements];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < elements.length; i++) {
|
||||||
|
|
||||||
|
// If jQuery is supported
|
||||||
|
if ($) {
|
||||||
|
$(elements[i]).on(event, callback);
|
||||||
|
|
||||||
|
// Default way to support events
|
||||||
|
} else if ('addEventListener' in elements[i]) {
|
||||||
|
elements[i].addEventListener(event, callback, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenience function to trigger event
|
||||||
|
* @param event {string} event type
|
||||||
|
* @param modal {string} id of modal that the event is triggered on
|
||||||
|
*/
|
||||||
|
trigger: function (event, modal) {
|
||||||
|
var eventTrigger;
|
||||||
|
var eventParams = {
|
||||||
|
detail: {
|
||||||
|
'modal': modal
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use jQuery to fire the event if it is included
|
||||||
|
if ($) {
|
||||||
|
$(document).trigger(event, eventParams);
|
||||||
|
|
||||||
|
// Use createEvent if supported (that's mostly the case)
|
||||||
|
} else if (document.createEvent) {
|
||||||
|
eventTrigger = document.createEvent('CustomEvent');
|
||||||
|
|
||||||
|
eventTrigger.initCustomEvent(event, false, false, {
|
||||||
|
'modal': modal
|
||||||
|
});
|
||||||
|
|
||||||
|
document.dispatchEvent(eventTrigger);
|
||||||
|
|
||||||
|
// Use CustomEvents if supported
|
||||||
|
} else {
|
||||||
|
eventTrigger = new CustomEvent(event, eventParams);
|
||||||
|
|
||||||
|
document.dispatchEvent(eventTrigger);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenience function to add a class to an element
|
||||||
|
* @param element {Node} element to add class to
|
||||||
|
* @param className {string}
|
||||||
|
*/
|
||||||
|
addClass: function (element, className) {
|
||||||
|
if (element && !element.className.match(className)) {
|
||||||
|
element.className += ' ' + className;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenience function to remove a class from an element
|
||||||
|
* @param element {Node} element to remove class off
|
||||||
|
* @param className {string}
|
||||||
|
*/
|
||||||
|
removeClass: function (element, className) {
|
||||||
|
element.className = element.className.replace(className, '').replace(' ', ' ');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function to check if an element has a class
|
||||||
|
* @param {Node} element Element to check classname on
|
||||||
|
* @param {string} className Class name to check for
|
||||||
|
* @return {Boolean} true, if class is available on modal
|
||||||
|
*/
|
||||||
|
hasClass: function (element, className) {
|
||||||
|
return !!element.className.match(className);
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Focus modal
|
||||||
|
*/
|
||||||
|
setFocus: function () {
|
||||||
|
if (modal.activeElement) {
|
||||||
|
|
||||||
|
// Set element with last focus
|
||||||
|
modal.lastActive = document.activeElement;
|
||||||
|
|
||||||
|
// New focussing
|
||||||
|
modal.activeElement.focus();
|
||||||
|
|
||||||
|
// Add handler to keep the focus
|
||||||
|
modal.keepFocus(modal.activeElement);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unfocus
|
||||||
|
*/
|
||||||
|
removeFocus: function () {
|
||||||
|
if (modal.lastActive) {
|
||||||
|
modal.lastActive.focus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keep focus inside the modal
|
||||||
|
* @param element {node} element to keep focus in
|
||||||
|
*/
|
||||||
|
keepFocus: function (element) {
|
||||||
|
var allTabbableElements = [];
|
||||||
|
|
||||||
|
// Don't keep the focus if the browser is unable to support
|
||||||
|
// CSS3 selectors
|
||||||
|
try {
|
||||||
|
allTabbableElements = element.querySelectorAll(modal.tabbableElements);
|
||||||
|
} catch (ex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstTabbableElement = modal.getFirstElementVisible(allTabbableElements);
|
||||||
|
var lastTabbableElement = modal.getLastElementVisible(allTabbableElements);
|
||||||
|
|
||||||
|
var focusHandler = function (event) {
|
||||||
|
var keyCode = event.which || event.keyCode;
|
||||||
|
|
||||||
|
// TAB pressed
|
||||||
|
if (keyCode !== 9) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Polyfill to prevent the default behavior of events
|
||||||
|
event.preventDefault = event.preventDefault || function () {
|
||||||
|
event.returnValue = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Move focus to first element that can be tabbed if Shift isn't used
|
||||||
|
if (event.target === lastTabbableElement && !event.shiftKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
firstTabbableElement.focus();
|
||||||
|
|
||||||
|
// Move focus to last element that can be tabbed if Shift is used
|
||||||
|
} else if (event.target === firstTabbableElement && event.shiftKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
lastTabbableElement.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
modal.on('keydown', element, focusHandler);
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the first visible element of a nodeList
|
||||||
|
*
|
||||||
|
* @param nodeList The nodelist to parse
|
||||||
|
* @return {Node|null} Returns a specific node or null if no element found
|
||||||
|
*/
|
||||||
|
getFirstElementVisible: function (nodeList) {
|
||||||
|
var nodeListLength = nodeList.length;
|
||||||
|
|
||||||
|
// If the first item is not visible
|
||||||
|
if (!modal.isElementVisible(nodeList[0])) {
|
||||||
|
for (var i = 1; i < nodeListLength - 1; i++) {
|
||||||
|
|
||||||
|
// Iterate elements in the NodeList, return the first visible
|
||||||
|
if (modal.isElementVisible(nodeList[i])) {
|
||||||
|
return nodeList[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nodeList[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the last visible element of a nodeList
|
||||||
|
*
|
||||||
|
* @param nodeList The nodelist to parse
|
||||||
|
* @return {Node|null} Returns a specific node or null if no element found
|
||||||
|
*/
|
||||||
|
getLastElementVisible: function (nodeList) {
|
||||||
|
var nodeListLength = nodeList.length;
|
||||||
|
var lastTabbableElement = nodeList[nodeListLength - 1];
|
||||||
|
|
||||||
|
// If the last item is not visible
|
||||||
|
if (!modal.isElementVisible(lastTabbableElement)) {
|
||||||
|
for (var i = nodeListLength - 1; i >= 0; i--) {
|
||||||
|
|
||||||
|
// Iterate elements in the NodeList, return the first visible
|
||||||
|
if (modal.isElementVisible(nodeList[i])) {
|
||||||
|
return nodeList[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return lastTabbableElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenience function to check if an element is visible
|
||||||
|
*
|
||||||
|
* Test idea taken from jQuery 1.3.2 source code
|
||||||
|
*
|
||||||
|
* @param element {Node} element to test
|
||||||
|
* @return {boolean} is the element visible or not
|
||||||
|
*/
|
||||||
|
isElementVisible: function (element) {
|
||||||
|
return !(element.offsetWidth === 0 && element.offsetHeight === 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark modal as active
|
||||||
|
* @param element {Node} element to set active
|
||||||
|
*/
|
||||||
|
setActive: function (element) {
|
||||||
|
modal.addClass(element, 'is-active');
|
||||||
|
modal.activeElement = element;
|
||||||
|
|
||||||
|
// Update aria-hidden
|
||||||
|
modal.activeElement.setAttribute('aria-hidden', 'false');
|
||||||
|
|
||||||
|
// Set the focus to the modal
|
||||||
|
modal.setFocus(element.id);
|
||||||
|
|
||||||
|
// Fire an event
|
||||||
|
modal.trigger('cssmodal:show', modal.activeElement);
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unset previous active modal
|
||||||
|
* @param isStacked {boolean} `true` if element is stacked above another
|
||||||
|
* @param shouldNotBeStacked {boolean} `true` if next element should be stacked
|
||||||
|
*/
|
||||||
|
unsetActive: function (isStacked, shouldNotBeStacked) {
|
||||||
|
modal.removeClass(document.documentElement, 'has-overlay');
|
||||||
|
|
||||||
|
if (modal.activeElement) {
|
||||||
|
modal.removeClass(modal.activeElement, 'is-active');
|
||||||
|
|
||||||
|
// Fire an event
|
||||||
|
modal.trigger('cssmodal:hide', modal.activeElement);
|
||||||
|
|
||||||
|
// Update aria-hidden
|
||||||
|
modal.activeElement.setAttribute('aria-hidden', 'true');
|
||||||
|
|
||||||
|
// Unfocus
|
||||||
|
modal.removeFocus();
|
||||||
|
|
||||||
|
// Make modal stacked if needed
|
||||||
|
if (isStacked && !shouldNotBeStacked) {
|
||||||
|
modal.stackModal(modal.activeElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are any stacked elements
|
||||||
|
if (!isStacked && modal.stackedElements.length > 0) {
|
||||||
|
modal.unstackModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset active element
|
||||||
|
modal.activeElement = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stackable modal
|
||||||
|
* @param stackableModal {node} element to be stacked
|
||||||
|
*/
|
||||||
|
stackModal: function (stackableModal) {
|
||||||
|
modal.addClass(stackableModal, 'is-stacked');
|
||||||
|
|
||||||
|
// Set modal as stacked
|
||||||
|
modal.stackedElements.push(modal.activeElement);
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reactivate stacked modal
|
||||||
|
*/
|
||||||
|
unstackModal: function () {
|
||||||
|
var stackedCount = modal.stackedElements.length;
|
||||||
|
var lastStacked = modal.stackedElements[stackedCount - 1];
|
||||||
|
|
||||||
|
modal.removeClass(lastStacked, 'is-stacked');
|
||||||
|
|
||||||
|
// Set hash to modal, activates the modal automatically
|
||||||
|
global.location.hash = lastStacked.id;
|
||||||
|
|
||||||
|
// Remove modal from stackedElements array
|
||||||
|
modal.stackedElements.splice(stackedCount - 1, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When displaying modal, prevent background from scrolling
|
||||||
|
* @param {Object} event The incoming hashChange event
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
mainHandler: function (event, noHash) {
|
||||||
|
var hash = global.location.hash.replace('#', '');
|
||||||
|
var index = 0;
|
||||||
|
var tmp = [];
|
||||||
|
var modalElement;
|
||||||
|
var modalChild;
|
||||||
|
|
||||||
|
// JS-only: no hash present
|
||||||
|
if (noHash) {
|
||||||
|
hash = event.currentTarget.getAttribute('href').replace('#', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
modalElement = document.getElementById(hash);
|
||||||
|
|
||||||
|
// Check if the hash contains an index
|
||||||
|
if (hash.indexOf('/') !== -1) {
|
||||||
|
tmp = hash.split('/');
|
||||||
|
index = tmp.pop();
|
||||||
|
hash = tmp.join('/');
|
||||||
|
|
||||||
|
// Remove the index from the hash...
|
||||||
|
modalElement = document.getElementById(hash);
|
||||||
|
|
||||||
|
// ... and store the index as a number on the element to
|
||||||
|
// make it accessible for plugins
|
||||||
|
if (!modalElement) {
|
||||||
|
throw new Error('ReferenceError: element "' + hash + '" does not exist!');
|
||||||
|
}
|
||||||
|
|
||||||
|
modalElement.index = (1 * index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the hash element exists
|
||||||
|
if (modalElement) {
|
||||||
|
|
||||||
|
// Polyfill to prevent the default behavior of events
|
||||||
|
try {
|
||||||
|
event.preventDefault();
|
||||||
|
} catch (ex) {
|
||||||
|
event.returnValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get first element in selected element
|
||||||
|
modalChild = modalElement.children[0];
|
||||||
|
|
||||||
|
// When we deal with a modal and body-class `has-overlay` is not set
|
||||||
|
if (modalChild && modalChild.className.match(/modal-inner/)) {
|
||||||
|
|
||||||
|
// Make previous element stackable if it is not the same modal
|
||||||
|
modal.unsetActive(
|
||||||
|
!modal.hasClass(modalElement, 'is-active'),
|
||||||
|
(modalElement.getAttribute('data-stackable') === 'false')
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set an html class to prevent scrolling
|
||||||
|
modal.addClass(document.documentElement, 'has-overlay');
|
||||||
|
|
||||||
|
// Set scroll position for modal
|
||||||
|
modal._currentScrollPositionY = global.scrollY;
|
||||||
|
modal._currentScrollPositionX = global.scrollX;
|
||||||
|
|
||||||
|
// Mark the active element
|
||||||
|
modal.setActive(modalElement);
|
||||||
|
modal.activeElement._noHash = noHash;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// If activeElement is already defined, delete it
|
||||||
|
modal.unsetActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject iframes
|
||||||
|
*/
|
||||||
|
injectIframes: function () {
|
||||||
|
var iframes = document.querySelectorAll('[data-iframe-src]');
|
||||||
|
var iframe;
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
for (; i < iframes.length; i++) {
|
||||||
|
iframe = document.createElement('iframe');
|
||||||
|
|
||||||
|
iframe.src = iframes[i].getAttribute('data-iframe-src');
|
||||||
|
iframe.setAttribute('webkitallowfullscreen', true);
|
||||||
|
iframe.setAttribute('mozallowfullscreen', true);
|
||||||
|
iframe.setAttribute('allowfullscreen', true);
|
||||||
|
|
||||||
|
iframes[i].appendChild(iframe);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to all relevant events
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
init: function () {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hide overlay when ESC is pressed
|
||||||
|
*/
|
||||||
|
this.on('keyup', document, function (event) {
|
||||||
|
var hash = global.location.hash.replace('#', '');
|
||||||
|
|
||||||
|
// If key ESC is pressed
|
||||||
|
if (event.keyCode === 27) {
|
||||||
|
if (modal.activeElement && hash === modal.activeElement.id) {
|
||||||
|
global.location.hash = '!';
|
||||||
|
} else {
|
||||||
|
modal.unsetActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modal.lastActive) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unfocus
|
||||||
|
modal.removeFocus();
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger main handler on click if hash is deactivated
|
||||||
|
*/
|
||||||
|
this.on('click', document.querySelectorAll('[data-cssmodal-nohash]'), function (event) {
|
||||||
|
modal.mainHandler(event, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// And close modal without hash
|
||||||
|
this.on('click', document.querySelectorAll('.modal-close'), function (event) {
|
||||||
|
if (modal.activeElement._noHash){
|
||||||
|
modal.mainHandler(event, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trigger main handler on load and hashchange
|
||||||
|
*/
|
||||||
|
this.on('hashchange', global, modal.mainHandler);
|
||||||
|
this.on('load', global, modal.mainHandler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent scrolling when modal is active
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
global.onscroll = global.onmousewheel = function () {
|
||||||
|
if (document.documentElement.className.match(/has-overlay/)) {
|
||||||
|
global.scrollTo(modal._currentScrollPositionX, modal._currentScrollPositionY);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject iframes
|
||||||
|
*/
|
||||||
|
modal.injectIframes();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AMD, module loader, global registration
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Expose modal for loaders that implement the Node module pattern.
|
||||||
|
if (typeof module === 'object' && module && typeof module.exports === 'object') {
|
||||||
|
module.exports = modal;
|
||||||
|
|
||||||
|
// Register as an AMD module
|
||||||
|
} else if (typeof define === 'function' && define.amd) {
|
||||||
|
define('CSSModal', [], function () {
|
||||||
|
|
||||||
|
// We use jQuery if the browser doesn't support CustomEvents
|
||||||
|
if (!global.CustomEvent && !$) {
|
||||||
|
throw new Error('This browser doesn\'t support CustomEvent - please include jQuery.');
|
||||||
|
}
|
||||||
|
|
||||||
|
modal.init();
|
||||||
|
|
||||||
|
return modal;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Export CSSModal into global space
|
||||||
|
} else if (typeof global === 'object' && typeof global.document === 'object') {
|
||||||
|
global.CSSModal = modal;
|
||||||
|
modal.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
}(window, window.jQuery));
|
46
Seenginx/wwwroot/js/ui.js
Normal file
46
Seenginx/wwwroot/js/ui.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
(function (window, document) {
|
||||||
|
|
||||||
|
var layout = document.getElementById('layout'),
|
||||||
|
menu = document.getElementById('menu'),
|
||||||
|
menuLink = document.getElementById('menuLink'),
|
||||||
|
content = document.getElementById('main');
|
||||||
|
|
||||||
|
function toggleClass(element, className) {
|
||||||
|
var classes = element.className.split(/\s+/),
|
||||||
|
length = classes.length,
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
for(; i < length; i++) {
|
||||||
|
if (classes[i] === className) {
|
||||||
|
classes.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The className is not found
|
||||||
|
if (length === classes.length) {
|
||||||
|
classes.push(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
element.className = classes.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleAll(e) {
|
||||||
|
var active = 'active';
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
toggleClass(layout, active);
|
||||||
|
toggleClass(menu, active);
|
||||||
|
toggleClass(menuLink, active);
|
||||||
|
}
|
||||||
|
|
||||||
|
menuLink.onclick = function (e) {
|
||||||
|
toggleAll(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
content.onclick = function(e) {
|
||||||
|
if (menu.className.indexOf('active') !== -1) {
|
||||||
|
toggleAll(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}(this, this.document));
|
Loading…
Reference in New Issue
Block a user