| @@ -0,0 +1,13 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| namespace MVCTemplate.Business.Dtos | |||
| { | |||
| public class BaseDto | |||
| { | |||
| public int Id { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,33 @@ | |||
| using AutoMapper; | |||
| using Microsoft.Extensions.DependencyInjection; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| namespace MVCTemplate.Business.Infrastructure.Extensions | |||
| { | |||
| public class StartupExtensions | |||
| { | |||
| public static void ConfigureServices(IServiceCollection services) | |||
| { | |||
| Data.Extensions.StartupExtensions.ConfigureServices(services); | |||
| // TODO: add all missing services | |||
| var mapperConfiguration = new MapperConfiguration(mc => | |||
| { | |||
| mc.AddProfile(new MapperProfile()); | |||
| }); | |||
| IMapper mapper = mapperConfiguration.CreateMapper(); | |||
| services.AddSingleton(mapper); | |||
| //services.AddLocalization(options => options.ResourcesPath = "Infrastructure/Resources"); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,18 @@ | |||
| using AutoMapper; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| using MVCTemplate.Data.Data; | |||
| using MVCTemplate.Business.Dtos; | |||
| namespace MVCTemplate.Business.Infrastructure | |||
| { | |||
| public class MapperProfile : Profile | |||
| { | |||
| public MapperProfile() | |||
| { | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,13 @@ | |||
| namespace MVCTemplate.Business.Infrastructure.Settings | |||
| { | |||
| public class EmailSettings | |||
| { | |||
| public string SmtpServer { get; set; } | |||
| public int SmtpPort { get; set; } | |||
| public bool SmtpUseSSL { get; set; } | |||
| public string SmtpUsername { get; set; } | |||
| public string SmtpPassword { get; set; } | |||
| public string SmtpFrom { get; set; } | |||
| public string SmtpFromName { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,29 @@ | |||
| using Microsoft.Extensions.Configuration; | |||
| using Microsoft.Extensions.DependencyInjection; | |||
| using System; | |||
| namespace MVCTemplate.Business.Infrastructure | |||
| { | |||
| public class StartupConfiguration | |||
| { | |||
| public static TConfig ConfigureStartupConfig<TConfig>(IServiceCollection services, IConfiguration configuration) where TConfig : class, new() | |||
| { | |||
| if (services == null) | |||
| throw new ArgumentNullException(nameof(services)); | |||
| if (configuration == null) | |||
| throw new ArgumentNullException(nameof(configuration)); | |||
| //create instance of config | |||
| var config = new TConfig(); | |||
| var classType = typeof(TConfig); | |||
| //bind it to the appropriate section of configuration | |||
| configuration.Bind(classType.Name, config); | |||
| //and register it as a service | |||
| services.AddSingleton(config); | |||
| return config; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,25 @@ | |||
| <Project Sdk="Microsoft.NET.Sdk"> | |||
| <PropertyGroup> | |||
| <TargetFramework>net5.0</TargetFramework> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="AutoMapper" Version="11.0.1" /> | |||
| <PackageReference Include="MailKit" Version="2.13.0" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="5.0.7" /> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.7" /> | |||
| <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" /> | |||
| <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <ProjectReference Include="..\MVCTemplate.Data\MVCTemplate.Data.csproj" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <Folder Include="Interfaces\" /> | |||
| <Folder Include="Services\" /> | |||
| </ItemGroup> | |||
| </Project> | |||
| @@ -0,0 +1,13 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| namespace MVCTemplate.Data.Data | |||
| { | |||
| public class BaseEntity | |||
| { | |||
| public int Id { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,20 @@ | |||
| using Microsoft.AspNetCore.Identity.EntityFrameworkCore; | |||
| using Microsoft.EntityFrameworkCore; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using MVCTemplate.Data.Data; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| namespace MVCTemplate.Data.DbContexts | |||
| { | |||
| public class AppDbContext : IdentityDbContext | |||
| { | |||
| public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } | |||
| } | |||
| } | |||
| @@ -0,0 +1,26 @@ | |||
| using Microsoft.Extensions.DependencyInjection; | |||
| using Microsoft.EntityFrameworkCore; | |||
| using Microsoft.Extensions.Configuration; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| using MVCTemplate.Data.DbContexts; | |||
| using Microsoft.AspNetCore.Identity; | |||
| namespace MVCTemplate.Data.Extensions | |||
| { | |||
| public class StartupExtensions | |||
| { | |||
| public static void ConfigureServices(IServiceCollection services) | |||
| { | |||
| var configuration = new ConfigurationBuilder() | |||
| .AddJsonFile(path: "appsettings.json") | |||
| .Build(); | |||
| services.AddDbContext<AppDbContext>(options => | |||
| options.UseSqlServer( | |||
| configuration.GetConnectionString("DefaultConnection"))); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| <Project Sdk="Microsoft.NET.Sdk"> | |||
| <PropertyGroup> | |||
| <TargetFramework>net5.0</TargetFramework> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="AutoMapper" Version="11.0.1" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="5.0.7" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.4" /> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.7" /> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.7" /> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.4"> | |||
| <PrivateAssets>all</PrivateAssets> | |||
| <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |||
| </PackageReference> | |||
| <PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" /> | |||
| <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" /> | |||
| </ItemGroup> | |||
| </Project> | |||
| @@ -0,0 +1,277 @@ | |||
| // <auto-generated /> | |||
| using System; | |||
| using Microsoft.EntityFrameworkCore; | |||
| using Microsoft.EntityFrameworkCore.Infrastructure; | |||
| using Microsoft.EntityFrameworkCore.Metadata; | |||
| using Microsoft.EntityFrameworkCore.Migrations; | |||
| using Microsoft.EntityFrameworkCore.Storage.ValueConversion; | |||
| using MVCTemplate.Data.DbContexts; | |||
| namespace MVCTemplate.Data.Migrations | |||
| { | |||
| [DbContext(typeof(AppDbContext))] | |||
| [Migration("20220906133332_init")] | |||
| partial class init | |||
| { | |||
| protected override void BuildTargetModel(ModelBuilder modelBuilder) | |||
| { | |||
| #pragma warning disable 612, 618 | |||
| modelBuilder | |||
| .HasAnnotation("Relational:MaxIdentifierLength", 128) | |||
| .HasAnnotation("ProductVersion", "5.0.7") | |||
| .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); | |||
| modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => | |||
| { | |||
| b.Property<string>("Id") | |||
| .HasColumnType("nvarchar(450)"); | |||
| b.Property<string>("ConcurrencyStamp") | |||
| .IsConcurrencyToken() | |||
| .HasColumnType("nvarchar(max)"); | |||
| b.Property<string>("Name") | |||
| .HasMaxLength(256) | |||
| .HasColumnType("nvarchar(256)"); | |||
| b.Property<string>("NormalizedName") | |||
| .HasMaxLength(256) | |||
| .HasColumnType("nvarchar(256)"); | |||
| b.HasKey("Id"); | |||
| b.HasIndex("NormalizedName") | |||
| .IsUnique() | |||
| .HasDatabaseName("RoleNameIndex") | |||
| .HasFilter("[NormalizedName] IS NOT NULL"); | |||
| b.ToTable("AspNetRoles"); | |||
| }); | |||
| modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => | |||
| { | |||
| b.Property<int>("Id") | |||
| .ValueGeneratedOnAdd() | |||
| .HasColumnType("int") | |||
| .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); | |||
| b.Property<string>("ClaimType") | |||
| .HasColumnType("nvarchar(max)"); | |||
| b.Property<string>("ClaimValue") | |||
| .HasColumnType("nvarchar(max)"); | |||
| b.Property<string>("RoleId") | |||
| .IsRequired() | |||
| .HasColumnType("nvarchar(450)"); | |||
| b.HasKey("Id"); | |||
| b.HasIndex("RoleId"); | |||
| b.ToTable("AspNetRoleClaims"); | |||
| }); | |||
| modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => | |||
| { | |||
| b.Property<string>("Id") | |||
| .HasColumnType("nvarchar(450)"); | |||
| b.Property<int>("AccessFailedCount") | |||
| .HasColumnType("int"); | |||
| b.Property<string>("ConcurrencyStamp") | |||
| .IsConcurrencyToken() | |||
| .HasColumnType("nvarchar(max)"); | |||
| b.Property<string>("Email") | |||
| .HasMaxLength(256) | |||
| .HasColumnType("nvarchar(256)"); | |||
| b.Property<bool>("EmailConfirmed") | |||
| .HasColumnType("bit"); | |||
| b.Property<bool>("LockoutEnabled") | |||
| .HasColumnType("bit"); | |||
| b.Property<DateTimeOffset?>("LockoutEnd") | |||
| .HasColumnType("datetimeoffset"); | |||
| b.Property<string>("NormalizedEmail") | |||
| .HasMaxLength(256) | |||
| .HasColumnType("nvarchar(256)"); | |||
| b.Property<string>("NormalizedUserName") | |||
| .HasMaxLength(256) | |||
| .HasColumnType("nvarchar(256)"); | |||
| b.Property<string>("PasswordHash") | |||
| .HasColumnType("nvarchar(max)"); | |||
| b.Property<string>("PhoneNumber") | |||
| .HasColumnType("nvarchar(max)"); | |||
| b.Property<bool>("PhoneNumberConfirmed") | |||
| .HasColumnType("bit"); | |||
| b.Property<string>("SecurityStamp") | |||
| .HasColumnType("nvarchar(max)"); | |||
| b.Property<bool>("TwoFactorEnabled") | |||
| .HasColumnType("bit"); | |||
| b.Property<string>("UserName") | |||
| .HasMaxLength(256) | |||
| .HasColumnType("nvarchar(256)"); | |||
| b.HasKey("Id"); | |||
| b.HasIndex("NormalizedEmail") | |||
| .HasDatabaseName("EmailIndex"); | |||
| b.HasIndex("NormalizedUserName") | |||
| .IsUnique() | |||
| .HasDatabaseName("UserNameIndex") | |||
| .HasFilter("[NormalizedUserName] IS NOT NULL"); | |||
| b.ToTable("AspNetUsers"); | |||
| }); | |||
| modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => | |||
| { | |||
| b.Property<int>("Id") | |||
| .ValueGeneratedOnAdd() | |||
| .HasColumnType("int") | |||
| .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); | |||
| b.Property<string>("ClaimType") | |||
| .HasColumnType("nvarchar(max)"); | |||
| b.Property<string>("ClaimValue") | |||
| .HasColumnType("nvarchar(max)"); | |||
| b.Property<string>("UserId") | |||
| .IsRequired() | |||
| .HasColumnType("nvarchar(450)"); | |||
| b.HasKey("Id"); | |||
| b.HasIndex("UserId"); | |||
| b.ToTable("AspNetUserClaims"); | |||
| }); | |||
| modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => | |||
| { | |||
| b.Property<string>("LoginProvider") | |||
| .HasMaxLength(128) | |||
| .HasColumnType("nvarchar(128)"); | |||
| b.Property<string>("ProviderKey") | |||
| .HasMaxLength(128) | |||
| .HasColumnType("nvarchar(128)"); | |||
| b.Property<string>("ProviderDisplayName") | |||
| .HasColumnType("nvarchar(max)"); | |||
| b.Property<string>("UserId") | |||
| .IsRequired() | |||
| .HasColumnType("nvarchar(450)"); | |||
| b.HasKey("LoginProvider", "ProviderKey"); | |||
| b.HasIndex("UserId"); | |||
| b.ToTable("AspNetUserLogins"); | |||
| }); | |||
| modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => | |||
| { | |||
| b.Property<string>("UserId") | |||
| .HasColumnType("nvarchar(450)"); | |||
| b.Property<string>("RoleId") | |||
| .HasColumnType("nvarchar(450)"); | |||
| b.HasKey("UserId", "RoleId"); | |||
| b.HasIndex("RoleId"); | |||
| b.ToTable("AspNetUserRoles"); | |||
| }); | |||
| modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => | |||
| { | |||
| b.Property<string>("UserId") | |||
| .HasColumnType("nvarchar(450)"); | |||
| b.Property<string>("LoginProvider") | |||
| .HasMaxLength(128) | |||
| .HasColumnType("nvarchar(128)"); | |||
| b.Property<string>("Name") | |||
| .HasMaxLength(128) | |||
| .HasColumnType("nvarchar(128)"); | |||
| b.Property<string>("Value") | |||
| .HasColumnType("nvarchar(max)"); | |||
| b.HasKey("UserId", "LoginProvider", "Name"); | |||
| b.ToTable("AspNetUserTokens"); | |||
| }); | |||
| modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => | |||
| { | |||
| b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) | |||
| .WithMany() | |||
| .HasForeignKey("RoleId") | |||
| .OnDelete(DeleteBehavior.Cascade) | |||
| .IsRequired(); | |||
| }); | |||
| modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => | |||
| { | |||
| b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) | |||
| .WithMany() | |||
| .HasForeignKey("UserId") | |||
| .OnDelete(DeleteBehavior.Cascade) | |||
| .IsRequired(); | |||
| }); | |||
| modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => | |||
| { | |||
| b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) | |||
| .WithMany() | |||
| .HasForeignKey("UserId") | |||
| .OnDelete(DeleteBehavior.Cascade) | |||
| .IsRequired(); | |||
| }); | |||
| modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => | |||
| { | |||
| b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) | |||
| .WithMany() | |||
| .HasForeignKey("RoleId") | |||
| .OnDelete(DeleteBehavior.Cascade) | |||
| .IsRequired(); | |||
| b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) | |||
| .WithMany() | |||
| .HasForeignKey("UserId") | |||
| .OnDelete(DeleteBehavior.Cascade) | |||
| .IsRequired(); | |||
| }); | |||
| modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => | |||
| { | |||
| b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) | |||
| .WithMany() | |||
| .HasForeignKey("UserId") | |||
| .OnDelete(DeleteBehavior.Cascade) | |||
| .IsRequired(); | |||
| }); | |||
| #pragma warning restore 612, 618 | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,219 @@ | |||
| using System; | |||
| using Microsoft.EntityFrameworkCore.Migrations; | |||
| namespace MVCTemplate.Data.Migrations | |||
| { | |||
| public partial class init : Migration | |||
| { | |||
| protected override void Up(MigrationBuilder migrationBuilder) | |||
| { | |||
| migrationBuilder.CreateTable( | |||
| name: "AspNetRoles", | |||
| columns: table => new | |||
| { | |||
| Id = table.Column<string>(type: "nvarchar(450)", nullable: false), | |||
| Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true), | |||
| NormalizedName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true), | |||
| ConcurrencyStamp = table.Column<string>(type: "nvarchar(max)", nullable: true) | |||
| }, | |||
| constraints: table => | |||
| { | |||
| table.PrimaryKey("PK_AspNetRoles", x => x.Id); | |||
| }); | |||
| migrationBuilder.CreateTable( | |||
| name: "AspNetUsers", | |||
| columns: table => new | |||
| { | |||
| Id = table.Column<string>(type: "nvarchar(450)", nullable: false), | |||
| UserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true), | |||
| NormalizedUserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true), | |||
| Email = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true), | |||
| NormalizedEmail = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true), | |||
| EmailConfirmed = table.Column<bool>(type: "bit", nullable: false), | |||
| PasswordHash = table.Column<string>(type: "nvarchar(max)", nullable: true), | |||
| SecurityStamp = table.Column<string>(type: "nvarchar(max)", nullable: true), | |||
| ConcurrencyStamp = table.Column<string>(type: "nvarchar(max)", nullable: true), | |||
| PhoneNumber = table.Column<string>(type: "nvarchar(max)", nullable: true), | |||
| PhoneNumberConfirmed = table.Column<bool>(type: "bit", nullable: false), | |||
| TwoFactorEnabled = table.Column<bool>(type: "bit", nullable: false), | |||
| LockoutEnd = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: true), | |||
| LockoutEnabled = table.Column<bool>(type: "bit", nullable: false), | |||
| AccessFailedCount = table.Column<int>(type: "int", nullable: false) | |||
| }, | |||
| constraints: table => | |||
| { | |||
| table.PrimaryKey("PK_AspNetUsers", x => x.Id); | |||
| }); | |||
| migrationBuilder.CreateTable( | |||
| name: "AspNetRoleClaims", | |||
| columns: table => new | |||
| { | |||
| Id = table.Column<int>(type: "int", nullable: false) | |||
| .Annotation("SqlServer:Identity", "1, 1"), | |||
| RoleId = table.Column<string>(type: "nvarchar(450)", nullable: false), | |||
| ClaimType = table.Column<string>(type: "nvarchar(max)", nullable: true), | |||
| ClaimValue = table.Column<string>(type: "nvarchar(max)", nullable: true) | |||
| }, | |||
| constraints: table => | |||
| { | |||
| table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); | |||
| table.ForeignKey( | |||
| name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", | |||
| column: x => x.RoleId, | |||
| principalTable: "AspNetRoles", | |||
| principalColumn: "Id", | |||
| onDelete: ReferentialAction.Cascade); | |||
| }); | |||
| migrationBuilder.CreateTable( | |||
| name: "AspNetUserClaims", | |||
| columns: table => new | |||
| { | |||
| Id = table.Column<int>(type: "int", nullable: false) | |||
| .Annotation("SqlServer:Identity", "1, 1"), | |||
| UserId = table.Column<string>(type: "nvarchar(450)", nullable: false), | |||
| ClaimType = table.Column<string>(type: "nvarchar(max)", nullable: true), | |||
| ClaimValue = table.Column<string>(type: "nvarchar(max)", nullable: true) | |||
| }, | |||
| constraints: table => | |||
| { | |||
| table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); | |||
| table.ForeignKey( | |||
| name: "FK_AspNetUserClaims_AspNetUsers_UserId", | |||
| column: x => x.UserId, | |||
| principalTable: "AspNetUsers", | |||
| principalColumn: "Id", | |||
| onDelete: ReferentialAction.Cascade); | |||
| }); | |||
| migrationBuilder.CreateTable( | |||
| name: "AspNetUserLogins", | |||
| columns: table => new | |||
| { | |||
| LoginProvider = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false), | |||
| ProviderKey = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false), | |||
| ProviderDisplayName = table.Column<string>(type: "nvarchar(max)", nullable: true), | |||
| UserId = table.Column<string>(type: "nvarchar(450)", nullable: false) | |||
| }, | |||
| constraints: table => | |||
| { | |||
| table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); | |||
| table.ForeignKey( | |||
| name: "FK_AspNetUserLogins_AspNetUsers_UserId", | |||
| column: x => x.UserId, | |||
| principalTable: "AspNetUsers", | |||
| principalColumn: "Id", | |||
| onDelete: ReferentialAction.Cascade); | |||
| }); | |||
| migrationBuilder.CreateTable( | |||
| name: "AspNetUserRoles", | |||
| columns: table => new | |||
| { | |||
| UserId = table.Column<string>(type: "nvarchar(450)", nullable: false), | |||
| RoleId = table.Column<string>(type: "nvarchar(450)", nullable: false) | |||
| }, | |||
| constraints: table => | |||
| { | |||
| table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); | |||
| table.ForeignKey( | |||
| name: "FK_AspNetUserRoles_AspNetRoles_RoleId", | |||
| column: x => x.RoleId, | |||
| principalTable: "AspNetRoles", | |||
| principalColumn: "Id", | |||
| onDelete: ReferentialAction.Cascade); | |||
| table.ForeignKey( | |||
| name: "FK_AspNetUserRoles_AspNetUsers_UserId", | |||
| column: x => x.UserId, | |||
| principalTable: "AspNetUsers", | |||
| principalColumn: "Id", | |||
| onDelete: ReferentialAction.Cascade); | |||
| }); | |||
| migrationBuilder.CreateTable( | |||
| name: "AspNetUserTokens", | |||
| columns: table => new | |||
| { | |||
| UserId = table.Column<string>(type: "nvarchar(450)", nullable: false), | |||
| LoginProvider = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false), | |||
| Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false), | |||
| Value = table.Column<string>(type: "nvarchar(max)", nullable: true) | |||
| }, | |||
| constraints: table => | |||
| { | |||
| table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); | |||
| table.ForeignKey( | |||
| name: "FK_AspNetUserTokens_AspNetUsers_UserId", | |||
| column: x => x.UserId, | |||
| principalTable: "AspNetUsers", | |||
| principalColumn: "Id", | |||
| onDelete: ReferentialAction.Cascade); | |||
| }); | |||
| migrationBuilder.CreateIndex( | |||
| name: "IX_AspNetRoleClaims_RoleId", | |||
| table: "AspNetRoleClaims", | |||
| column: "RoleId"); | |||
| migrationBuilder.CreateIndex( | |||
| name: "RoleNameIndex", | |||
| table: "AspNetRoles", | |||
| column: "NormalizedName", | |||
| unique: true, | |||
| filter: "[NormalizedName] IS NOT NULL"); | |||
| migrationBuilder.CreateIndex( | |||
| name: "IX_AspNetUserClaims_UserId", | |||
| table: "AspNetUserClaims", | |||
| column: "UserId"); | |||
| migrationBuilder.CreateIndex( | |||
| name: "IX_AspNetUserLogins_UserId", | |||
| table: "AspNetUserLogins", | |||
| column: "UserId"); | |||
| migrationBuilder.CreateIndex( | |||
| name: "IX_AspNetUserRoles_RoleId", | |||
| table: "AspNetUserRoles", | |||
| column: "RoleId"); | |||
| migrationBuilder.CreateIndex( | |||
| name: "EmailIndex", | |||
| table: "AspNetUsers", | |||
| column: "NormalizedEmail"); | |||
| migrationBuilder.CreateIndex( | |||
| name: "UserNameIndex", | |||
| table: "AspNetUsers", | |||
| column: "NormalizedUserName", | |||
| unique: true, | |||
| filter: "[NormalizedUserName] IS NOT NULL"); | |||
| } | |||
| protected override void Down(MigrationBuilder migrationBuilder) | |||
| { | |||
| migrationBuilder.DropTable( | |||
| name: "AspNetRoleClaims"); | |||
| migrationBuilder.DropTable( | |||
| name: "AspNetUserClaims"); | |||
| migrationBuilder.DropTable( | |||
| name: "AspNetUserLogins"); | |||
| migrationBuilder.DropTable( | |||
| name: "AspNetUserRoles"); | |||
| migrationBuilder.DropTable( | |||
| name: "AspNetUserTokens"); | |||
| migrationBuilder.DropTable( | |||
| name: "AspNetRoles"); | |||
| migrationBuilder.DropTable( | |||
| name: "AspNetUsers"); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,44 @@ | |||
| | |||
| Microsoft Visual Studio Solution File, Format Version 12.00 | |||
| # Visual Studio Version 16 | |||
| VisualStudioVersion = 16.0.31321.278 | |||
| MinimumVisualStudioVersion = 10.0.40219.1 | |||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MVCTemplate", "MVCTemplate\MVCTemplate.csproj", "{495FB586-0B0F-4368-87A3-C13444149D2A}" | |||
| ProjectSection(ProjectDependencies) = postProject | |||
| {941012BA-66F3-4B72-A735-CC199A3E4E7D} = {941012BA-66F3-4B72-A735-CC199A3E4E7D} | |||
| {263779FB-D285-44F3-BE46-81E019A17610} = {263779FB-D285-44F3-BE46-81E019A17610} | |||
| EndProjectSection | |||
| EndProject | |||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MVCTemplate.Business", "MVCTemplate.Business\MVCTemplate.Business.csproj", "{263779FB-D285-44F3-BE46-81E019A17610}" | |||
| ProjectSection(ProjectDependencies) = postProject | |||
| {941012BA-66F3-4B72-A735-CC199A3E4E7D} = {941012BA-66F3-4B72-A735-CC199A3E4E7D} | |||
| EndProjectSection | |||
| EndProject | |||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MVCTemplate.Data", "MVCTemplate.Data\MVCTemplate.Data.csproj", "{941012BA-66F3-4B72-A735-CC199A3E4E7D}" | |||
| EndProject | |||
| Global | |||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
| Debug|Any CPU = Debug|Any CPU | |||
| Release|Any CPU = Release|Any CPU | |||
| EndGlobalSection | |||
| GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||
| {495FB586-0B0F-4368-87A3-C13444149D2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
| {495FB586-0B0F-4368-87A3-C13444149D2A}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
| {495FB586-0B0F-4368-87A3-C13444149D2A}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
| {495FB586-0B0F-4368-87A3-C13444149D2A}.Release|Any CPU.Build.0 = Release|Any CPU | |||
| {263779FB-D285-44F3-BE46-81E019A17610}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
| {263779FB-D285-44F3-BE46-81E019A17610}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
| {263779FB-D285-44F3-BE46-81E019A17610}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
| {263779FB-D285-44F3-BE46-81E019A17610}.Release|Any CPU.Build.0 = Release|Any CPU | |||
| {941012BA-66F3-4B72-A735-CC199A3E4E7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
| {941012BA-66F3-4B72-A735-CC199A3E4E7D}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
| {941012BA-66F3-4B72-A735-CC199A3E4E7D}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
| {941012BA-66F3-4B72-A735-CC199A3E4E7D}.Release|Any CPU.Build.0 = Release|Any CPU | |||
| EndGlobalSection | |||
| GlobalSection(SolutionProperties) = preSolution | |||
| HideSolutionNode = FALSE | |||
| EndGlobalSection | |||
| GlobalSection(ExtensibilityGlobals) = postSolution | |||
| SolutionGuid = {8D821E45-1525-4207-A292-08C0388BBF06} | |||
| EndGlobalSection | |||
| EndGlobal | |||
| @@ -0,0 +1,12 @@ | |||
| { | |||
| "version": 1, | |||
| "isRoot": true, | |||
| "tools": { | |||
| "dotnet-ef": { | |||
| "version": "5.0.7", | |||
| "commands": [ | |||
| "dotnet-ef" | |||
| ] | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| using System; | |||
| using Microsoft.AspNetCore.Hosting; | |||
| using Microsoft.AspNetCore.Identity; | |||
| using Microsoft.AspNetCore.Identity.UI; | |||
| using Microsoft.EntityFrameworkCore; | |||
| using Microsoft.Extensions.Configuration; | |||
| using Microsoft.Extensions.DependencyInjection; | |||
| using MVCTemplate.Data.DbContexts; | |||
| [assembly: HostingStartup(typeof(MVCTemplate.Areas.Identity.IdentityHostingStartup))] | |||
| namespace MVCTemplate.Areas.Identity | |||
| { | |||
| public class IdentityHostingStartup : IHostingStartup | |||
| { | |||
| public void Configure(IWebHostBuilder builder) | |||
| { | |||
| builder.ConfigureServices((context, services) => { | |||
| }); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,85 @@ | |||
| @page | |||
| @model LoginModel | |||
| @{ | |||
| ViewData["Title"] = "Log in"; | |||
| } | |||
| <h1>@ViewData["Title"]</h1> | |||
| <div class="row"> | |||
| <div class="col-md-4"> | |||
| <section> | |||
| <form id="account" method="post"> | |||
| <h4>Use a local account to log in.</h4> | |||
| <hr /> | |||
| <div asp-validation-summary="All" class="text-danger"></div> | |||
| <div class="form-group"> | |||
| <label asp-for="Input.Email"></label> | |||
| <input asp-for="Input.Email" class="form-control" /> | |||
| <span asp-validation-for="Input.Email" class="text-danger"></span> | |||
| </div> | |||
| <div class="form-group"> | |||
| <label asp-for="Input.Password"></label> | |||
| <input asp-for="Input.Password" class="form-control" /> | |||
| <span asp-validation-for="Input.Password" class="text-danger"></span> | |||
| </div> | |||
| <div class="form-group"> | |||
| <div class="checkbox"> | |||
| <label asp-for="Input.RememberMe"> | |||
| <input asp-for="Input.RememberMe" /> | |||
| @Html.DisplayNameFor(m => m.Input.RememberMe) | |||
| </label> | |||
| </div> | |||
| </div> | |||
| <div class="form-group"> | |||
| <button type="submit" class="btn btn-primary">Log in</button> | |||
| </div> | |||
| <div class="form-group"> | |||
| <p> | |||
| <a id="forgot-password" asp-page="./ForgotPassword">Forgot your password?</a> | |||
| </p> | |||
| <p> | |||
| <a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a> | |||
| </p> | |||
| <p> | |||
| <a id="resend-confirmation" asp-page="./ResendEmailConfirmation">Resend email confirmation</a> | |||
| </p> | |||
| </div> | |||
| </form> | |||
| </section> | |||
| </div> | |||
| <div class="col-md-6 col-md-offset-2"> | |||
| <section> | |||
| <h4>Use another service to log in.</h4> | |||
| <hr /> | |||
| @{ | |||
| if ((Model.ExternalLogins?.Count ?? 0) == 0) | |||
| { | |||
| <div> | |||
| <p> | |||
| There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a> | |||
| for details on setting up this ASP.NET application to support logging in via external services. | |||
| </p> | |||
| </div> | |||
| } | |||
| else | |||
| { | |||
| <form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal"> | |||
| <div> | |||
| <p> | |||
| @foreach (var provider in Model.ExternalLogins) | |||
| { | |||
| <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button> | |||
| } | |||
| </p> | |||
| </div> | |||
| </form> | |||
| } | |||
| } | |||
| </section> | |||
| </div> | |||
| </div> | |||
| @section Scripts { | |||
| <partial name="_ValidationScriptsPartial" /> | |||
| } | |||
| @@ -0,0 +1,110 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.ComponentModel.DataAnnotations; | |||
| using System.Linq; | |||
| using System.Text.Encodings.Web; | |||
| using System.Threading.Tasks; | |||
| using Microsoft.AspNetCore.Authorization; | |||
| using Microsoft.AspNetCore.Authentication; | |||
| using Microsoft.AspNetCore.Identity; | |||
| using Microsoft.AspNetCore.Identity.UI.Services; | |||
| using Microsoft.AspNetCore.Mvc; | |||
| using Microsoft.AspNetCore.Mvc.RazorPages; | |||
| using Microsoft.Extensions.Logging; | |||
| namespace MVCTemplate.Areas.Identity.Pages.Account | |||
| { | |||
| [AllowAnonymous] | |||
| public class LoginModel : PageModel | |||
| { | |||
| private readonly UserManager<IdentityUser> _userManager; | |||
| private readonly SignInManager<IdentityUser> _signInManager; | |||
| private readonly ILogger<LoginModel> _logger; | |||
| public LoginModel(SignInManager<IdentityUser> signInManager, | |||
| ILogger<LoginModel> logger, | |||
| UserManager<IdentityUser> userManager) | |||
| { | |||
| _userManager = userManager; | |||
| _signInManager = signInManager; | |||
| _logger = logger; | |||
| } | |||
| [BindProperty] | |||
| public InputModel Input { get; set; } | |||
| public IList<AuthenticationScheme> ExternalLogins { get; set; } | |||
| public string ReturnUrl { get; set; } | |||
| [TempData] | |||
| public string ErrorMessage { get; set; } | |||
| public class InputModel | |||
| { | |||
| [Required] | |||
| [EmailAddress] | |||
| public string Email { get; set; } | |||
| [Required] | |||
| [DataType(DataType.Password)] | |||
| public string Password { get; set; } | |||
| [Display(Name = "Remember me?")] | |||
| public bool RememberMe { get; set; } | |||
| } | |||
| public async Task OnGetAsync(string returnUrl = null) | |||
| { | |||
| if (!string.IsNullOrEmpty(ErrorMessage)) | |||
| { | |||
| ModelState.AddModelError(string.Empty, ErrorMessage); | |||
| } | |||
| returnUrl ??= Url.Content("~/"); | |||
| // Clear the existing external cookie to ensure a clean login process | |||
| await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme); | |||
| ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); | |||
| ReturnUrl = returnUrl; | |||
| } | |||
| public async Task<IActionResult> OnPostAsync(string returnUrl = null) | |||
| { | |||
| returnUrl ??= Url.Content("~/"); | |||
| ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); | |||
| if (ModelState.IsValid) | |||
| { | |||
| // This doesn't count login failures towards account lockout | |||
| // To enable password failures to trigger account lockout, set lockoutOnFailure: true | |||
| var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false); | |||
| if (result.Succeeded) | |||
| { | |||
| _logger.LogInformation("User logged in."); | |||
| return LocalRedirect(returnUrl); | |||
| } | |||
| if (result.RequiresTwoFactor) | |||
| { | |||
| return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe }); | |||
| } | |||
| if (result.IsLockedOut) | |||
| { | |||
| _logger.LogWarning("User account locked out."); | |||
| return RedirectToPage("./Lockout"); | |||
| } | |||
| else | |||
| { | |||
| ModelState.AddModelError(string.Empty, "Invalid login attempt."); | |||
| return Page(); | |||
| } | |||
| } | |||
| // If we got this far, something failed, redisplay form | |||
| return Page(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,67 @@ | |||
| @page | |||
| @model RegisterModel | |||
| @{ | |||
| ViewData["Title"] = "Register"; | |||
| } | |||
| <h1>@ViewData["Title"]</h1> | |||
| <div class="row"> | |||
| <div class="col-md-4"> | |||
| <form asp-route-returnUrl="@Model.ReturnUrl" method="post"> | |||
| <h4>Create a new account.</h4> | |||
| <hr /> | |||
| <div asp-validation-summary="All" class="text-danger"></div> | |||
| <div class="form-group"> | |||
| <label asp-for="Input.Email"></label> | |||
| <input asp-for="Input.Email" class="form-control" /> | |||
| <span asp-validation-for="Input.Email" class="text-danger"></span> | |||
| </div> | |||
| <div class="form-group"> | |||
| <label asp-for="Input.Password"></label> | |||
| <input asp-for="Input.Password" class="form-control" /> | |||
| <span asp-validation-for="Input.Password" class="text-danger"></span> | |||
| </div> | |||
| <div class="form-group"> | |||
| <label asp-for="Input.ConfirmPassword"></label> | |||
| <input asp-for="Input.ConfirmPassword" class="form-control" /> | |||
| <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span> | |||
| </div> | |||
| <button type="submit" class="btn btn-primary">Register</button> | |||
| </form> | |||
| </div> | |||
| <div class="col-md-6 col-md-offset-2"> | |||
| <section> | |||
| <h4>Use another service to register.</h4> | |||
| <hr /> | |||
| @{ | |||
| if ((Model.ExternalLogins?.Count ?? 0) == 0) | |||
| { | |||
| <div> | |||
| <p> | |||
| There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a> | |||
| for details on setting up this ASP.NET application to support logging in via external services. | |||
| </p> | |||
| </div> | |||
| } | |||
| else | |||
| { | |||
| <form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal"> | |||
| <div> | |||
| <p> | |||
| @foreach (var provider in Model.ExternalLogins) | |||
| { | |||
| <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button> | |||
| } | |||
| </p> | |||
| </div> | |||
| </form> | |||
| } | |||
| } | |||
| </section> | |||
| </div> | |||
| </div> | |||
| @section Scripts { | |||
| <partial name="_ValidationScriptsPartial" /> | |||
| } | |||
| @@ -0,0 +1,114 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.ComponentModel.DataAnnotations; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Text.Encodings.Web; | |||
| using System.Threading.Tasks; | |||
| using Microsoft.AspNetCore.Authentication; | |||
| using Microsoft.AspNetCore.Authorization; | |||
| using Microsoft.AspNetCore.Identity; | |||
| using Microsoft.AspNetCore.Identity.UI.Services; | |||
| using Microsoft.AspNetCore.Mvc; | |||
| using Microsoft.AspNetCore.Mvc.RazorPages; | |||
| using Microsoft.AspNetCore.WebUtilities; | |||
| using Microsoft.Extensions.Logging; | |||
| namespace MVCTemplate.Areas.Identity.Pages.Account | |||
| { | |||
| [AllowAnonymous] | |||
| public class RegisterModel : PageModel | |||
| { | |||
| private readonly SignInManager<IdentityUser> _signInManager; | |||
| private readonly UserManager<IdentityUser> _userManager; | |||
| private readonly ILogger<RegisterModel> _logger; | |||
| private readonly IEmailSender _emailSender; | |||
| public RegisterModel( | |||
| UserManager<IdentityUser> userManager, | |||
| SignInManager<IdentityUser> signInManager, | |||
| ILogger<RegisterModel> logger, | |||
| IEmailSender emailSender) | |||
| { | |||
| _userManager = userManager; | |||
| _signInManager = signInManager; | |||
| _logger = logger; | |||
| _emailSender = emailSender; | |||
| } | |||
| [BindProperty] | |||
| public InputModel Input { get; set; } | |||
| public string ReturnUrl { get; set; } | |||
| public IList<AuthenticationScheme> ExternalLogins { get; set; } | |||
| public class InputModel | |||
| { | |||
| [Required] | |||
| [EmailAddress] | |||
| [Display(Name = "Email")] | |||
| public string Email { get; set; } | |||
| [Required] | |||
| [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] | |||
| [DataType(DataType.Password)] | |||
| [Display(Name = "Password")] | |||
| public string Password { get; set; } | |||
| [DataType(DataType.Password)] | |||
| [Display(Name = "Confirm password")] | |||
| [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] | |||
| public string ConfirmPassword { get; set; } | |||
| } | |||
| public async Task OnGetAsync(string returnUrl = null) | |||
| { | |||
| ReturnUrl = returnUrl; | |||
| ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); | |||
| } | |||
| public async Task<IActionResult> OnPostAsync(string returnUrl = null) | |||
| { | |||
| returnUrl ??= Url.Content("~/"); | |||
| ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); | |||
| if (ModelState.IsValid) | |||
| { | |||
| var user = new IdentityUser { UserName = Input.Email, Email = Input.Email }; | |||
| var result = await _userManager.CreateAsync(user, Input.Password); | |||
| if (result.Succeeded) | |||
| { | |||
| _logger.LogInformation("User created a new account with password."); | |||
| var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); | |||
| code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); | |||
| var callbackUrl = Url.Page( | |||
| "/Account/ConfirmEmail", | |||
| pageHandler: null, | |||
| values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl }, | |||
| protocol: Request.Scheme); | |||
| await _emailSender.SendEmailAsync(Input.Email, "Confirm your email", | |||
| $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>."); | |||
| if (_userManager.Options.SignIn.RequireConfirmedAccount) | |||
| { | |||
| return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl }); | |||
| } | |||
| else | |||
| { | |||
| await _signInManager.SignInAsync(user, isPersistent: false); | |||
| return LocalRedirect(returnUrl); | |||
| } | |||
| } | |||
| foreach (var error in result.Errors) | |||
| { | |||
| ModelState.AddModelError(string.Empty, error.Description); | |||
| } | |||
| } | |||
| // If we got this far, something failed, redisplay form | |||
| return Page(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,37 @@ | |||
| @page | |||
| @model ResetPasswordModel | |||
| @{ | |||
| ViewData["Title"] = "Reset password"; | |||
| } | |||
| <h1>@ViewData["Title"]</h1> | |||
| <h4>Reset your password.</h4> | |||
| <hr /> | |||
| <div class="row"> | |||
| <div class="col-md-4"> | |||
| <form method="post"> | |||
| <div asp-validation-summary="ModelOnly" class="text-danger"></div> | |||
| <input asp-for="Input.Code" type="hidden" /> | |||
| <div class="form-group"> | |||
| <label asp-for="Input.Email"></label> | |||
| <input asp-for="Input.Email" class="form-control" /> | |||
| <span asp-validation-for="Input.Email" class="text-danger"></span> | |||
| </div> | |||
| <div class="form-group"> | |||
| <label asp-for="Input.Password"></label> | |||
| <input asp-for="Input.Password" class="form-control" /> | |||
| <span asp-validation-for="Input.Password" class="text-danger"></span> | |||
| </div> | |||
| <div class="form-group"> | |||
| <label asp-for="Input.ConfirmPassword"></label> | |||
| <input asp-for="Input.ConfirmPassword" class="form-control" /> | |||
| <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span> | |||
| </div> | |||
| <button type="submit" class="btn btn-primary">Reset</button> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| @section Scripts { | |||
| <partial name="_ValidationScriptsPartial" /> | |||
| } | |||
| @@ -0,0 +1,91 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.ComponentModel.DataAnnotations; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| using System.Web; | |||
| using Microsoft.AspNetCore.Authorization; | |||
| using Microsoft.AspNetCore.Identity; | |||
| using Microsoft.AspNetCore.Mvc; | |||
| using Microsoft.AspNetCore.Mvc.RazorPages; | |||
| using Microsoft.AspNetCore.WebUtilities; | |||
| namespace MVCTemplate.Areas.Identity.Pages.Account | |||
| { | |||
| [AllowAnonymous] | |||
| public class ResetPasswordModel : PageModel | |||
| { | |||
| private readonly UserManager<IdentityUser> _userManager; | |||
| public ResetPasswordModel(UserManager<IdentityUser> userManager) | |||
| { | |||
| _userManager = userManager; | |||
| } | |||
| [BindProperty] | |||
| public InputModel Input { get; set; } | |||
| public class InputModel | |||
| { | |||
| [Required] | |||
| [EmailAddress] | |||
| public string Email { get; set; } | |||
| [Required] | |||
| [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] | |||
| [DataType(DataType.Password)] | |||
| public string Password { get; set; } | |||
| [DataType(DataType.Password)] | |||
| [Display(Name = "Confirm password")] | |||
| [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] | |||
| public string ConfirmPassword { get; set; } | |||
| public string Code { get; set; } | |||
| } | |||
| public IActionResult OnGet(string code = null) | |||
| { | |||
| if (code == null) | |||
| { | |||
| return BadRequest("A code must be supplied for password reset."); | |||
| } | |||
| else | |||
| { | |||
| Input = new InputModel | |||
| { | |||
| Code = code | |||
| }; | |||
| return Page(); | |||
| } | |||
| } | |||
| public async Task<IActionResult> OnPostAsync() | |||
| { | |||
| if (!ModelState.IsValid) | |||
| { | |||
| return Page(); | |||
| } | |||
| var user = await _userManager.FindByEmailAsync(Input.Email); | |||
| if (user == null) | |||
| { | |||
| // Don't reveal that the user does not exist | |||
| return RedirectToPage("./ResetPasswordConfirmation"); | |||
| } | |||
| var result = await _userManager.ResetPasswordAsync(user, Input.Code, Input.Password); | |||
| if (result.Succeeded) | |||
| { | |||
| return RedirectToPage("./ResetPasswordConfirmation"); | |||
| } | |||
| foreach (var error in result.Errors) | |||
| { | |||
| ModelState.AddModelError(string.Empty, error.Description); | |||
| } | |||
| return Page(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1 @@ | |||
| @using MVCTemplate.Areas.Identity.Pages.Account | |||
| @@ -0,0 +1,18 @@ | |||
| <environment include="Development"> | |||
| <script src="~/Identity/lib/jquery-validation/dist/jquery.validate.js"></script> | |||
| <script src="~/Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script> | |||
| </environment> | |||
| <environment exclude="Development"> | |||
| <script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.17.0/jquery.validate.min.js" | |||
| asp-fallback-src="~/Identity/lib/jquery-validation/dist/jquery.validate.min.js" | |||
| asp-fallback-test="window.jQuery && window.jQuery.validator" | |||
| crossorigin="anonymous" | |||
| integrity="sha384-rZfj/ogBloos6wzLGpPkkOr/gpkBNLZ6b6yLy4o+ok+t/SAKlL5mvXLr0OXNi1Hp"> | |||
| </script> | |||
| <script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.9/jquery.validate.unobtrusive.min.js" | |||
| asp-fallback-src="~/Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js" | |||
| asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive" | |||
| crossorigin="anonymous" | |||
| integrity="sha384-ifv0TYDWxBHzvAk2Z0n8R434FL1Rlv/Av18DXE43N/1rvHyOG4izKst0f2iSLdds"> | |||
| </script> | |||
| </environment> | |||
| @@ -0,0 +1,4 @@ | |||
| @using Microsoft.AspNetCore.Identity | |||
| @using MVCTemplate.Areas.Identity | |||
| @using MVCTemplate.Areas.Identity.Pages | |||
| @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers | |||
| @@ -0,0 +1,4 @@ | |||
| | |||
| @{ | |||
| Layout = "/Views/Shared/_Layout.cshtml"; | |||
| } | |||
| @@ -0,0 +1,41 @@ | |||
| using Microsoft.AspNetCore.Authorization; | |||
| using Microsoft.AspNetCore.Mvc; | |||
| using Microsoft.Extensions.Logging; | |||
| using Newtonsoft.Json; | |||
| using MVCTemplate.Business.Dtos; | |||
| using MVCTemplate.Models; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Diagnostics; | |||
| using System.Linq; | |||
| using System.Threading.Tasks; | |||
| using MVCTemplate.Infrastructure; | |||
| namespace MVCTemplate.Controllers | |||
| { | |||
| [Authorize] | |||
| public class HomeController : Controller | |||
| { | |||
| private readonly ILogger<HomeController> _logger; | |||
| public HomeController(ILogger<HomeController> logger) | |||
| { | |||
| _logger = logger; | |||
| } | |||
| public IActionResult Index() | |||
| { | |||
| return View(); | |||
| } | |||
| public IActionResult Privacy() | |||
| { | |||
| return View(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,11 @@ | |||
| using MVCTemplate.Business.Dtos; | |||
| using MVCTemplate.Models; | |||
| using System.Threading.Tasks; | |||
| namespace MVCTemplate.Infrastructure | |||
| { | |||
| public interface IModelFactory | |||
| { | |||
| } | |||
| } | |||
| @@ -0,0 +1,66 @@ | |||
| using Microsoft.AspNetCore.Hosting; | |||
| using Microsoft.AspNetCore.Http; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Net; | |||
| using System.Threading.Tasks; | |||
| using Newtonsoft.Json; | |||
| using Serilog; | |||
| namespace MVCTemplate.Infrastructure.Middleware | |||
| { | |||
| public class ExceptionHandlingMiddleware | |||
| { | |||
| private RequestDelegate nextRequestDelegate; | |||
| private IWebHostEnvironment environment; | |||
| public ExceptionHandlingMiddleware( | |||
| RequestDelegate nextRequestDelegate, | |||
| IWebHostEnvironment environment | |||
| ) | |||
| { | |||
| this.nextRequestDelegate = nextRequestDelegate ?? throw new ArgumentNullException(nameof(nextRequestDelegate)); | |||
| this.environment = environment ?? throw new ArgumentNullException(nameof(environment)); | |||
| } | |||
| public async Task Invoke(HttpContext context) | |||
| { | |||
| try | |||
| { | |||
| context.TraceIdentifier = Guid.NewGuid().ToString(); | |||
| await this.nextRequestDelegate(context); | |||
| } | |||
| catch (Exception ex) | |||
| { | |||
| await this.HandleGlobalExceptionAsync(context, ex); | |||
| } | |||
| } | |||
| private async Task HandleGlobalExceptionAsync(HttpContext context, Exception ex) | |||
| { | |||
| try | |||
| { | |||
| await this.WriteResponseAsync(context, HttpStatusCode.InternalServerError, JsonConvert.SerializeObject(ex.Message)); | |||
| } | |||
| catch (Exception e) | |||
| { | |||
| await this.WriteResponseAsync(context, HttpStatusCode.InternalServerError, JsonConvert.SerializeObject(e.Message)); | |||
| } | |||
| var logger = new LoggerConfiguration() | |||
| .MinimumLevel.Debug() | |||
| .WriteTo.File(@"AppData\Errors\log-.log", rollingInterval: RollingInterval.Day) | |||
| .CreateLogger(); | |||
| logger.Error(ex, "Unhandled Exception"/* - Detected UserId: {UserId}" /*, context.User.GetUserId()*/); | |||
| } | |||
| private async Task WriteResponseAsync(HttpContext context, HttpStatusCode code, string jsonResponse) | |||
| { | |||
| context.Response.ContentType = "application/json"; | |||
| context.Response.StatusCode = (int)code; | |||
| await context.Response.WriteAsync(jsonResponse); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,36 @@ | |||
| <Project Sdk="Microsoft.NET.Sdk.Web"> | |||
| <PropertyGroup> | |||
| <TargetFramework>net5.0</TargetFramework> | |||
| <CopyRefAssembliesToPublishDirectory>false</CopyRefAssembliesToPublishDirectory> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="AutoMapper" Version="11.0.1" /> | |||
| <PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.3" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="5.0.7" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="5.0.6" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.6" /> | |||
| <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="5.0.7" /> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.7" /> | |||
| <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.6"> | |||
| <PrivateAssets>all</PrivateAssets> | |||
| <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |||
| </PackageReference> | |||
| <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.2" /> | |||
| <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> | |||
| <PackageReference Include="Quartz" Version="3.4.0" /> | |||
| <PackageReference Include="Serilog" Version="2.10.0" /> | |||
| <PackageReference Include="Serilog.AspNetCore" Version="4.1.0" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <ProjectReference Include="..\MVCTemplate.Business\MVCTemplate.Business.csproj" /> | |||
| <ProjectReference Include="..\MVCTemplate.Data\MVCTemplate.Data.csproj" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <Folder Include="AppData\Errors\" /> | |||
| </ItemGroup> | |||
| </Project> | |||
| @@ -0,0 +1,11 @@ | |||
| using System; | |||
| namespace MVCTemplate.Models | |||
| { | |||
| public class ErrorViewModel | |||
| { | |||
| public string RequestId { get; set; } | |||
| public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); | |||
| } | |||
| } | |||
| @@ -0,0 +1,26 @@ | |||
| using Microsoft.AspNetCore.Hosting; | |||
| using Microsoft.Extensions.Configuration; | |||
| using Microsoft.Extensions.Hosting; | |||
| using Microsoft.Extensions.Logging; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Threading.Tasks; | |||
| namespace MVCTemplate | |||
| { | |||
| public class Program | |||
| { | |||
| public static void Main(string[] args) | |||
| { | |||
| CreateHostBuilder(args).Build().Run(); | |||
| } | |||
| public static IHostBuilder CreateHostBuilder(string[] args) => | |||
| Host.CreateDefaultBuilder(args) | |||
| .ConfigureWebHostDefaults(webBuilder => | |||
| { | |||
| webBuilder.UseStartup<Startup>(); | |||
| }); | |||
| } | |||
| } | |||
| @@ -0,0 +1,30 @@ | |||
| { | |||
| "iisSettings": { | |||
| "windowsAuthentication": false, | |||
| "anonymousAuthentication": true, | |||
| "iisExpress": { | |||
| "applicationUrl": "http://localhost:24744", | |||
| "sslPort": 44336 | |||
| } | |||
| }, | |||
| "profiles": { | |||
| "IIS Express": { | |||
| "commandName": "IISExpress", | |||
| "launchBrowser": true, | |||
| "environmentVariables": { | |||
| "ASPNETCORE_ENVIRONMENT": "Development", | |||
| "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" | |||
| } | |||
| }, | |||
| "MVCTemplate": { | |||
| "commandName": "Project", | |||
| "dotnetRunMessages": "true", | |||
| "launchBrowser": true, | |||
| "applicationUrl": "https://localhost:5001;http://localhost:5000", | |||
| "environmentVariables": { | |||
| "ASPNETCORE_ENVIRONMENT": "Development", | |||
| "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,3 @@ | |||
| Support for ASP.NET Core Identity was added to your project. | |||
| For setup and configuration information, see https://go.microsoft.com/fwlink/?linkid=2116645. | |||
| @@ -0,0 +1,70 @@ | |||
| using Microsoft.AspNetCore.Builder; | |||
| using Microsoft.AspNetCore.Hosting; | |||
| using Microsoft.AspNetCore.HttpsPolicy; | |||
| using Microsoft.AspNetCore.Identity; | |||
| using Microsoft.Extensions.Configuration; | |||
| using Microsoft.Extensions.DependencyInjection; | |||
| using Microsoft.Extensions.Hosting; | |||
| using MVCTemplate.Business.Infrastructure; | |||
| using MVCTemplate.Business.Infrastructure.Extensions; | |||
| using MVCTemplate.Business.Infrastructure.Settings; | |||
| using MVCTemplate.Data.DbContexts; | |||
| using MVCTemplate.Infrastructure.Middleware; | |||
| namespace MVCTemplate | |||
| { | |||
| public class Startup | |||
| { | |||
| public Startup(IConfiguration configuration) | |||
| { | |||
| Configuration = configuration; | |||
| } | |||
| public IConfiguration Configuration { get; } | |||
| // This method gets called by the runtime. Use this method to add services to the container. | |||
| public void ConfigureServices(IServiceCollection services) | |||
| { | |||
| StartupConfiguration.ConfigureStartupConfig<EmailSettings>(services, Configuration); | |||
| services.AddControllersWithViews(); | |||
| services.AddRazorPages(); | |||
| StartupExtensions.ConfigureServices(services); | |||
| services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = false) | |||
| .AddDefaultUI() | |||
| .AddRoles<IdentityRole>() | |||
| .AddEntityFrameworkStores<AppDbContext>(); | |||
| } | |||
| // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | |||
| public void Configure(IApplicationBuilder app, IWebHostEnvironment env) | |||
| { | |||
| if (env.IsDevelopment()) | |||
| { | |||
| app.UseDeveloperExceptionPage(); | |||
| } | |||
| else | |||
| { | |||
| app.UseExceptionHandler("/Home/Error"); | |||
| // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. | |||
| app.UseHsts(); | |||
| } | |||
| app.UseHttpsRedirection(); | |||
| app.UseStaticFiles(); | |||
| app.UseRouting(); | |||
| app.UseAuthentication(); | |||
| app.UseAuthorization(); | |||
| app.UseMiddleware(typeof(ExceptionHandlingMiddleware)); | |||
| app.UseEndpoints(endpoints => | |||
| { | |||
| endpoints.MapControllerRoute( | |||
| name: "default", | |||
| pattern: "{controller=Home}/{action=Index}/{id?}"); | |||
| endpoints.MapRazorPages(); | |||
| }); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,3 @@ | |||
| @{ | |||
| Layout = "~/Views/Shared/_Layout.cshtml"; | |||
| } | |||
| @@ -0,0 +1,6 @@ | |||
| @{ | |||
| ViewData["Title"] = "Privacy Policy"; | |||
| } | |||
| <h1>@ViewData["Title"]</h1> | |||
| <p>Use this page to detail your site's privacy policy.</p> | |||
| @@ -0,0 +1,25 @@ | |||
| @model ErrorViewModel | |||
| @{ | |||
| ViewData["Title"] = "Error"; | |||
| } | |||
| <h1 class="text-danger">Error.</h1> | |||
| <h2 class="text-danger">An error occurred while processing your request.</h2> | |||
| @if (Model.ShowRequestId) | |||
| { | |||
| <p> | |||
| <strong>Request ID:</strong> <code>@Model.RequestId</code> | |||
| </p> | |||
| } | |||
| <h3>Development Mode</h3> | |||
| <p> | |||
| Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred. | |||
| </p> | |||
| <p> | |||
| <strong>The Development environment shouldn't be enabled for deployed applications.</strong> | |||
| It can result in displaying sensitive information from exceptions to end users. | |||
| For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong> | |||
| and restarting the app. | |||
| </p> | |||
| @@ -0,0 +1,111 @@ | |||
| @{ | |||
| var controller = ViewContext.RouteData.Values["Controller"]; | |||
| var action = ViewContext.RouteData.Values["Action"]; | |||
| } | |||
| <!DOCTYPE html> | |||
| <html lang="en"> | |||
| <head> | |||
| <meta charset="utf-8" /> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |||
| <title>@ViewData["Title"] - MVCTemplate</title> | |||
| <!-- Google Font: Source Sans Pro --> | |||
| <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback"> | |||
| <!-- Font Awesome --> | |||
| <link rel="stylesheet" href="~/plugins/fontawesome-free/css/all.min.css"> | |||
| <!-- Ionicons --> | |||
| <link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css"> | |||
| <!-- Tempusdominus Bootstrap 4 --> | |||
| <link rel="stylesheet" href="~/plugins/tempusdominus-bootstrap-4/css/tempusdominus-bootstrap-4.min.css"> | |||
| <!-- iCheck --> | |||
| <link rel="stylesheet" href="~/plugins/icheck-bootstrap/icheck-bootstrap.min.css"> | |||
| <!-- JQVMap --> | |||
| <link rel="stylesheet" href="~/plugins/jqvmap/jqvmap.min.css"> | |||
| <!-- Theme style --> | |||
| <link rel="stylesheet" href="~/dist/css/adminlte.min.css"> | |||
| <!-- overlayScrollbars --> | |||
| <link rel="stylesheet" href="~/plugins/overlayScrollbars/css/OverlayScrollbars.min.css"> | |||
| <!-- Daterange picker --> | |||
| <link rel="stylesheet" href="~/plugins/daterangepicker/daterangepicker.css"> | |||
| <!-- summernote --> | |||
| <link rel="stylesheet" href="~/plugins/summernote/summernote-bs4.min.css"> | |||
| <link href="~/lib/jquery-confirm/jquery-confirm.min.css" rel="stylesheet" /> | |||
| <link rel="stylesheet" href="~/css/site.css"> | |||
| </head> | |||
| <body class="hold-transition layout-fixed"> | |||
| <noscript><p>Your browser does not support JavaScript. You need it enabled to do testing.</p></noscript> | |||
| <div class="wrapper"> | |||
| <div class="content-wrapper default-layout"> | |||
| <section class="content"> | |||
| <main role="main" class="pb-3"> | |||
| <div class="content-fluid"> | |||
| <div> </div> | |||
| <div class="card"> | |||
| <div class="card-body"> | |||
| @RenderBody() | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </main> | |||
| </section> | |||
| </div> | |||
| <footer class="main-footer ml-0"> | |||
| <strong>Copyright © 2021 <a href="https://dilig.net/">Diligent Software</a>.</strong> | |||
| All rights reserved. | |||
| <div class="float-right d-none d-sm-inline-block"> | |||
| <b>Version</b> 1.0.0-alpha | |||
| </div> | |||
| </footer> | |||
| </div> | |||
| <!-- jQuery --> | |||
| <script src="~/plugins/jquery/jquery.min.js"></script> | |||
| <!-- jQuery UI 1.11.4 --> | |||
| <script src="~/plugins/jquery-ui/jquery-ui.min.js"></script> | |||
| <!-- Resolve conflict in jQuery UI tooltip with Bootstrap tooltip --> | |||
| <script> | |||
| $.widget.bridge('uibutton', $.ui.button) | |||
| </script> | |||
| <!-- Bootstrap 4 --> | |||
| <script src="~/plugins/bootstrap/js/bootstrap.bundle.min.js"></script> | |||
| <!-- ChartJS --> | |||
| <script src="~/plugins/chart.js/Chart.min.js"></script> | |||
| <!-- Sparkline --> | |||
| <script src="~/plugins/sparklines/sparkline.js"></script> | |||
| <!-- JQVMap --> | |||
| <script src="~/plugins/jqvmap/jquery.vmap.min.js"></script> | |||
| <script src="~/plugins/jqvmap/maps/jquery.vmap.usa.js"></script> | |||
| <!-- jQuery Knob Chart --> | |||
| <script src="~/plugins/jquery-knob/jquery.knob.min.js"></script> | |||
| <!-- daterangepicker --> | |||
| <script src="~/plugins/moment/moment.min.js"></script> | |||
| <script src="~/plugins/daterangepicker/daterangepicker.js"></script> | |||
| <!-- Tempusdominus Bootstrap 4 --> | |||
| <script src="~/plugins/tempusdominus-bootstrap-4/js/tempusdominus-bootstrap-4.min.js"></script> | |||
| <!-- Summernote --> | |||
| <script src="~/plugins/summernote/summernote-bs4.min.js"></script> | |||
| <!-- overlayScrollbars --> | |||
| <script src="~/plugins/overlayScrollbars/js/jquery.overlayScrollbars.min.js"></script> | |||
| <!-- AdminLTE App --> | |||
| <script src="~/dist/js/adminlte.js"></script> | |||
| <!-- JQery Confirm --> | |||
| <script src="~/lib/alertifyjs/alertify.min.js"></script> | |||
| <script src="~/lib/blockUI/jquery.blockUI.js"></script> | |||
| <script src="~/js/site.js" asp-append-version="true"></script> | |||
| @await RenderSectionAsync("Scripts", required: false) | |||
| </body> | |||
| </html> | |||
| @@ -0,0 +1,264 @@ | |||
| @*@{ | |||
| var controller = ViewContext.RouteData.Values["Controller"]; | |||
| var action = ViewContext.RouteData.Values["Action"]; | |||
| } | |||
| <!DOCTYPE html> | |||
| <html lang="en"> | |||
| <head> | |||
| <meta charset="utf-8" /> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |||
| <title>@ViewData["Title"] - MVCTemplate</title> | |||
| <!-- Google Font: Source Sans Pro --> | |||
| <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback"> | |||
| <!-- Font Awesome --> | |||
| <link rel="stylesheet" href="~/plugins/fontawesome-free/css/all.min.css"> | |||
| <link rel="stylesheet" href="~/css/site.css"> | |||
| <!-- Ionicons --> | |||
| <link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css"> | |||
| <!-- Tempusdominus Bootstrap 4 --> | |||
| <link rel="stylesheet" href="~/plugins/tempusdominus-bootstrap-4/css/tempusdominus-bootstrap-4.min.css"> | |||
| <!-- iCheck --> | |||
| <link rel="stylesheet" href="~/plugins/icheck-bootstrap/icheck-bootstrap.min.css"> | |||
| <!-- JQVMap --> | |||
| <link rel="stylesheet" href="~/plugins/jqvmap/jqvmap.min.css"> | |||
| <!-- Theme style --> | |||
| <link rel="stylesheet" href="~/dist/css/adminlte.min.css"> | |||
| <!-- overlayScrollbars --> | |||
| <link rel="stylesheet" href="~/plugins/overlayScrollbars/css/OverlayScrollbars.min.css"> | |||
| <!-- Daterange picker --> | |||
| <link rel="stylesheet" href="~/plugins/daterangepicker/daterangepicker.css"> | |||
| <!-- summernote --> | |||
| <link rel="stylesheet" href="~/plugins/summernote/summernote-bs4.min.css"> | |||
| <!-- summernote --> | |||
| <link rel="stylesheet" href="~/plugins/datatables-bs4/css/dataTables.bootstrap4.min.css"> | |||
| <link rel="stylesheet" href="~/plugins/datatables-responsive/css/responsive.bootstrap4.min.css"> | |||
| <link rel="stylesheet" href="~/plugins/datatables-buttons/css/buttons.bootstrap4.min.css"> | |||
| <link rel="stylesheet" href="~/plugins/datatables-rowreorder/css/rowReorder.bootstrap4.min.css"> | |||
| <link rel="stylesheet" href="~/plugins/select2/css/select2.css"> | |||
| <link rel="stylesheet" href="~/plugins/select2-bootstrap4-theme/select2-bootstrap4.min.css"> | |||
| <link href="~/lib/jquery-confirm/jquery-confirm.min.css" rel="stylesheet" /> | |||
| <link rel="stylesheet" href="~/css/site.css"> | |||
| </head> | |||
| <body class="hold-transition sidebar-mini layout-fixed"> | |||
| <div class="wrapper"> | |||
| <header> | |||
| <!-- Navbar --> | |||
| <nav class="main-header navbar navbar-expand navbar-white navbar-light"> | |||
| <!-- Left navbar links --> | |||
| <ul class="navbar-nav"> | |||
| <li class="nav-item"> | |||
| <a class="nav-link" data-widget="pushmenu" href="#" role="button"><i class="fas fa-bars"></i></a> | |||
| </li> | |||
| </ul> | |||
| <!-- Right navbar links --> | |||
| <ul class="navbar-nav ml-auto"> | |||
| <!-- User Dropdown Menu --> | |||
| <li class="nav-item dropdown"> | |||
| <a class="nav-link" data-toggle="dropdown" href="#"> | |||
| <i class="far fa-user"></i> @User.FindFirst(System.Security.Claims.ClaimTypes.Email).Value | |||
| </a> | |||
| <div class="dropdown-menu dropdown-menu-right"> | |||
| <a href="#" class="dropdown-item"> | |||
| <i class="fas fa-cog mr-2"></i> Profile | |||
| </a> | |||
| <a href="/Identity/Account/LogOut" class="dropdown-item"> | |||
| <i class="fas fa-sign-out-alt mr-2"></i> Log Out | |||
| </a> | |||
| </div> | |||
| </li> | |||
| </ul> | |||
| </nav> | |||
| <!-- /.navbar --> | |||
| </header> | |||
| <!-- Main Sidebar Container --> | |||
| <aside class="main-sidebar sidebar-dark-purple elevation-4"> | |||
| <!-- Brand Logo --> | |||
| <a href="#" class="brand-link"> | |||
| <img src="~/dist/img/AdminLTELogo.png" alt="AdminLTE Logo" class="brand-image img-circle elevation-3" style="opacity: .8"> | |||
| <span class="brand-text font-weight-light">Screening test</span> | |||
| </a> | |||
| <!-- Sidebar --> | |||
| <div class="sidebar"> | |||
| <!-- SidebarSearch Form --> | |||
| <div class="form-inline"> | |||
| <div class="input-group" data-widget="sidebar-search"> | |||
| <input class="form-control form-control-sidebar" type="search" placeholder="Search" aria-label="Search"> | |||
| <div class="input-group-append"> | |||
| <button class="btn btn-sidebar"> | |||
| <i class="fas fa-search fa-fw"></i> | |||
| </button> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <!-- Sidebar Menu --> | |||
| <nav class="mt-2"> | |||
| <ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false"> | |||
| <!-- Add icons to the links using the .nav-icon class | |||
| with font-awesome or any other icon font library --> | |||
| <li class="nav-item menu-open"> | |||
| <a href="#" class='nav-link @(action.ToString() == "Users" || action.ToString() == "Invites" ? "active" : "")'> | |||
| <i class="nav-icon fas fa-tachometer-alt"></i> | |||
| <p> | |||
| Dashboard | |||
| <i class="right fas fa-angle-left"></i> | |||
| </p> | |||
| </a> | |||
| <ul class="nav nav-treeview"> | |||
| <li class="nav-item"> | |||
| <a href="#" class='nav-link @(action.ToString() == "Statistics" ? "active" : "")'> | |||
| <i class="far fa-circle nav-icon"></i> | |||
| <p>Statistics</p> | |||
| </a> | |||
| </li> | |||
| <li class='nav-item'> | |||
| <a asp-controller="Manage" asp-action="Users" class='nav-link @(action.ToString() == "Users" ? "active" : "")'> | |||
| <i class="far fa-circle nav-icon"></i> | |||
| <p>Users</p> | |||
| </a> | |||
| </li> | |||
| <li class='nav-item'> | |||
| <a asp-controller="Manage" asp-action="Invites" class='nav-link @(action.ToString() == "Invites" ? "active" : "")'> | |||
| <i class="far fa-circle nav-icon"></i> | |||
| <p>Invites</p> | |||
| </a> | |||
| </li> | |||
| </ul> | |||
| </li> | |||
| <li class="nav-item menu-open"> | |||
| <a href="#" class='nav-link @(action.ToString() == "Tests" || action.ToString() == "Questions" ? "active" : "")'> | |||
| <i class='nav-icon fas fa-scroll'></i> | |||
| <p> | |||
| Test Management | |||
| <i class="right fas fa-angle-left"></i> | |||
| </p> | |||
| </a> | |||
| <ul class="nav nav-treeview"> | |||
| <li class="nav-item"> | |||
| <a asp-controller="Manage" asp-action="Tests" class='nav-link @(action.ToString() == "Tests" ? "active" : "")'> | |||
| <i class="far fa-circle nav-icon"></i> | |||
| <p>Tests</p> | |||
| </a> | |||
| </li> | |||
| <li class="nav-item"> | |||
| <a asp-controller="Manage" asp-action="Questions" class='nav-link @(action.ToString() == "Questions" ? "active" : "")'> | |||
| <i class="far fa-circle nav-icon"></i> | |||
| <p>Questions</p> | |||
| </a> | |||
| </li> | |||
| </ul> | |||
| </li> | |||
| <li class="nav-item menu-open"> | |||
| <a href="#" class='nav-link @(action.ToString() == "Categories" ? "active" : "")'> | |||
| <i class="nav-icon fas fa-cog"></i> | |||
| <p> | |||
| Settings | |||
| <i class="right fas fa-angle-left"></i> | |||
| </p> | |||
| </a> | |||
| <ul class="nav nav-treeview"> | |||
| <li class="nav-item"> | |||
| <a asp-controller="Manage" asp-action="Categories" class='nav-link @(action.ToString() == "Categories" ? "active" : "")'> | |||
| <i class="far fa-circle nav-icon"></i> | |||
| <p>Categories</p> | |||
| </a> | |||
| </li> | |||
| </ul> | |||
| </li> | |||
| </ul> | |||
| </nav> | |||
| <!-- /.sidebar-menu --> | |||
| </div> | |||
| <!-- /.sidebar --> | |||
| </aside> | |||
| <div class="content-wrapper"> | |||
| <section class="content"> | |||
| <main role="main" class="pb-3"> | |||
| @RenderBody() | |||
| </main> | |||
| </section> | |||
| </div> | |||
| <footer class="main-footer"> | |||
| <strong>Copyright © 2021 <a href="https://dilig.net/">Diligent Software</a>.</strong> | |||
| All rights reserved. | |||
| <div class="float-right d-none d-sm-inline-block"> | |||
| <b>Version</b> 1.0.0-alpha | |||
| </div> | |||
| </footer> | |||
| </div> | |||
| <!-- jQuery --> | |||
| <script src="~/plugins/jquery/jquery.min.js"></script> | |||
| <!-- jQuery UI 1.11.4 --> | |||
| <script src="~/plugins/jquery-ui/jquery-ui.min.js"></script> | |||
| <!-- Resolve conflict in jQuery UI tooltip with Bootstrap tooltip --> | |||
| <script> | |||
| $.widget.bridge('uibutton', $.ui.button) | |||
| </script> | |||
| <!-- Bootstrap 4 --> | |||
| <script src="~/plugins/bootstrap/js/bootstrap.bundle.min.js"></script> | |||
| <!-- ChartJS --> | |||
| <script src="~/plugins/chart.js/Chart.min.js"></script> | |||
| <!-- Sparkline --> | |||
| <script src="~/plugins/sparklines/sparkline.js"></script> | |||
| <!-- JQVMap --> | |||
| <script src="~/plugins/jqvmap/jquery.vmap.min.js"></script> | |||
| <script src="~/plugins/jqvmap/maps/jquery.vmap.usa.js"></script> | |||
| <!-- jQuery Knob Chart --> | |||
| <script src="~/plugins/jquery-knob/jquery.knob.min.js"></script> | |||
| <!-- daterangepicker --> | |||
| <script src="~/plugins/moment/moment.min.js"></script> | |||
| <script src="~/plugins/daterangepicker/daterangepicker.js"></script> | |||
| <!-- Tempusdominus Bootstrap 4 --> | |||
| <script src="~/plugins/tempusdominus-bootstrap-4/js/tempusdominus-bootstrap-4.min.js"></script> | |||
| <!-- Summernote --> | |||
| <script src="~/plugins/summernote/summernote-bs4.min.js"></script> | |||
| <!-- overlayScrollbars --> | |||
| <script src="~/plugins/overlayScrollbars/js/jquery.overlayScrollbars.min.js"></script> | |||
| <!-- AdminLTE App --> | |||
| <script src="~/dist/js/adminlte.js"></script> | |||
| <script src="~/plugins/datatables/jquery.dataTables.min.js"></script> | |||
| <script src="~/plugins/datatables-bs4/js/dataTables.bootstrap4.min.js"></script> | |||
| <script src="~/plugins/datatables-responsive/js/dataTables.responsive.min.js"></script> | |||
| <script src="~/plugins/datatables-responsive/js/responsive.bootstrap4.min.js"></script> | |||
| <script src="~/plugins/datatables-buttons/js/dataTables.buttons.min.js"></script> | |||
| <script src="~/plugins/datatables-buttons/js/buttons.bootstrap4.min.js"></script> | |||
| <script src="~/plugins/jszip/jszip.min.js"></script> | |||
| <script src="~/plugins/pdfmake/pdfmake.min.js"></script> | |||
| <script src="~/plugins/pdfmake/vfs_fonts.js"></script> | |||
| <script src="~/plugins/datatables-buttons/js/buttons.html5.min.js"></script> | |||
| <script src="~/plugins/datatables-buttons/js/buttons.print.min.js"></script> | |||
| <script src="~/plugins/datatables-buttons/js/buttons.colVis.min.js"></script> | |||
| <script src="~/plugins/datatables-rowreorder/js/dataTables.rowReorder.min.js"></script> | |||
| <script src="~/plugins/datatables-rowreorder/js/rowReorder.bootstrap4.min.js"></script> | |||
| <script src="~/plugins/select2/js/select2.min.js"></script> | |||
| <!-- JQery Confirm --> | |||
| <script src="~/lib/jquery-confirm/jquery-confirm.min.js"></script> | |||
| <script src="~/lib/alertifyjs/alertify.min.js"></script> | |||
| <script src="~/lib/blockUI/jquery.blockUI.js"></script> | |||
| <script src="~/js/site.js" asp-append-version="true"></script> | |||
| @await RenderSectionAsync("Scripts", required: false) | |||
| </body> | |||
| </html> | |||
| *@ | |||
| @@ -0,0 +1,28 @@ | |||
| @*@using Microsoft.AspNetCore.Identity | |||
| @inject SignInManager<IdentityUser> SignInManager | |||
| @inject UserManager<IdentityUser> UserManager | |||
| <ul class="navbar-nav"> | |||
| @if (SignInManager.IsSignedIn(User)) | |||
| { | |||
| <li class="nav-item"> | |||
| <a id="manage" class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello @UserManager.GetUserName(User)!</a> | |||
| </li> | |||
| <li class="nav-item"> | |||
| <form id="logoutForm" class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Action("Index", "Home", new { area = "" })"> | |||
| <button id="logout" type="submit" class="nav-link btn btn-link text-dark">Logout</button> | |||
| </form> | |||
| </li> | |||
| } | |||
| else | |||
| { | |||
| <li class="nav-item"> | |||
| <a class="nav-link text-dark" id="register" asp-area="Identity" asp-page="/Account/Register">Register</a> | |||
| </li> | |||
| <li class="nav-item"> | |||
| <a class="nav-link text-dark" id="login" asp-area="Identity" asp-page="/Account/Login">Login</a> | |||
| </li> | |||
| } | |||
| </ul> | |||
| *@ | |||
| @@ -0,0 +1,2 @@ | |||
| <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script> | |||
| <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script> | |||
| @@ -0,0 +1,3 @@ | |||
| @using MVCTemplate | |||
| @using MVCTemplate.Models | |||
| @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers | |||
| @@ -0,0 +1,3 @@ | |||
| @{ | |||
| Layout = "_Layout"; | |||
| } | |||
| @@ -0,0 +1,9 @@ | |||
| { | |||
| "Logging": { | |||
| "LogLevel": { | |||
| "Default": "Information", | |||
| "Microsoft": "Warning", | |||
| "Microsoft.Hosting.Lifetime": "Information" | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,16 @@ | |||
| { | |||
| "AllowedHosts": "*", | |||
| "ConnectionStrings": { | |||
| "DefaultConnection": "data source=(localdb)\\MSSQLLocalDB; initial catalog=Test;Integrated Security=True" | |||
| }, | |||
| "Logging": { | |||
| "LogLevel": { | |||
| "Default": "Information", | |||
| "Microsoft": "Warning", | |||
| "Microsoft.Hosting.Lifetime": "Information" | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,14 @@ | |||
| { | |||
| "env": { | |||
| "browser": false, | |||
| "node": true | |||
| }, | |||
| "parserOptions": { | |||
| "sourceType": "script" | |||
| }, | |||
| "extends": "../../.eslintrc.json", | |||
| "rules": { | |||
| "no-console": "off", | |||
| "strict": "error" | |||
| } | |||
| } | |||
| @@ -0,0 +1,17 @@ | |||
| 'use strict' | |||
| module.exports = { | |||
| map: { | |||
| inline: false, | |||
| annotation: true, | |||
| sourcesContent: true | |||
| }, | |||
| plugins: [ | |||
| require('postcss-scrollbar')({ | |||
| edgeAutohide: true | |||
| }), | |||
| require('autoprefixer')({ | |||
| cascade: false | |||
| }) | |||
| ] | |||
| } | |||
| @@ -0,0 +1,32 @@ | |||
| 'use strict' | |||
| const { babel } = require('@rollup/plugin-babel') | |||
| const pkg = require('../../package') | |||
| const year = new Date().getFullYear() | |||
| const banner = `/*! | |||
| * AdminLTE v${pkg.version} (${pkg.homepage}) | |||
| * Copyright 2014-${year} ${pkg.author} | |||
| * Licensed under MIT (https://github.com/ColorlibHQ/AdminLTE/blob/master/LICENSE) | |||
| */` | |||
| module.exports = { | |||
| input: 'build/js/AdminLTE.js', | |||
| output: { | |||
| banner, | |||
| file: 'dist/js/adminlte.js', | |||
| format: 'umd', | |||
| globals: { | |||
| jquery: 'jQuery' | |||
| }, | |||
| name: 'adminlte' | |||
| }, | |||
| external: ['jquery'], | |||
| plugins: [ | |||
| babel({ | |||
| exclude: 'node_modules/**', | |||
| // Include the helpers in the bundle, at most one copy of each | |||
| babelHelpers: 'bundled' | |||
| }) | |||
| ] | |||
| } | |||
| @@ -0,0 +1,33 @@ | |||
| import CardRefresh from './CardRefresh' | |||
| import CardWidget from './CardWidget' | |||
| import ControlSidebar from './ControlSidebar' | |||
| import DirectChat from './DirectChat' | |||
| import Dropdown from './Dropdown' | |||
| import ExpandableTable from './ExpandableTable' | |||
| import Fullscreen from './Fullscreen' | |||
| import IFrame from './IFrame' | |||
| import Layout from './Layout' | |||
| import PushMenu from './PushMenu' | |||
| import SidebarSearch from './SidebarSearch' | |||
| import NavbarSearch from './NavbarSearch' | |||
| import Toasts from './Toasts' | |||
| import TodoList from './TodoList' | |||
| import Treeview from './Treeview' | |||
| export { | |||
| CardRefresh, | |||
| CardWidget, | |||
| ControlSidebar, | |||
| DirectChat, | |||
| Dropdown, | |||
| ExpandableTable, | |||
| Fullscreen, | |||
| IFrame, | |||
| Layout, | |||
| PushMenu, | |||
| SidebarSearch, | |||
| NavbarSearch, | |||
| Toasts, | |||
| TodoList, | |||
| Treeview | |||
| } | |||
| @@ -0,0 +1,153 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE CardRefresh.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'CardRefresh' | |||
| const DATA_KEY = 'lte.cardrefresh' | |||
| const EVENT_KEY = `.${DATA_KEY}` | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const EVENT_LOADED = `loaded${EVENT_KEY}` | |||
| const EVENT_OVERLAY_ADDED = `overlay.added${EVENT_KEY}` | |||
| const EVENT_OVERLAY_REMOVED = `overlay.removed${EVENT_KEY}` | |||
| const CLASS_NAME_CARD = 'card' | |||
| const SELECTOR_CARD = `.${CLASS_NAME_CARD}` | |||
| const SELECTOR_DATA_REFRESH = '[data-card-widget="card-refresh"]' | |||
| const Default = { | |||
| source: '', | |||
| sourceSelector: '', | |||
| params: {}, | |||
| trigger: SELECTOR_DATA_REFRESH, | |||
| content: '.card-body', | |||
| loadInContent: true, | |||
| loadOnInit: true, | |||
| responseType: '', | |||
| overlayTemplate: '<div class="overlay"><i class="fas fa-2x fa-sync-alt fa-spin"></i></div>', | |||
| onLoadStart() {}, | |||
| onLoadDone(response) { | |||
| return response | |||
| } | |||
| } | |||
| class CardRefresh { | |||
| constructor(element, settings) { | |||
| this._element = element | |||
| this._parent = element.parents(SELECTOR_CARD).first() | |||
| this._settings = $.extend({}, Default, settings) | |||
| this._overlay = $(this._settings.overlayTemplate) | |||
| if (element.hasClass(CLASS_NAME_CARD)) { | |||
| this._parent = element | |||
| } | |||
| if (this._settings.source === '') { | |||
| throw new Error('Source url was not defined. Please specify a url in your CardRefresh source option.') | |||
| } | |||
| } | |||
| load() { | |||
| this._addOverlay() | |||
| this._settings.onLoadStart.call($(this)) | |||
| $.get(this._settings.source, this._settings.params, response => { | |||
| if (this._settings.loadInContent) { | |||
| if (this._settings.sourceSelector !== '') { | |||
| response = $(response).find(this._settings.sourceSelector).html() | |||
| } | |||
| this._parent.find(this._settings.content).html(response) | |||
| } | |||
| this._settings.onLoadDone.call($(this), response) | |||
| this._removeOverlay() | |||
| }, this._settings.responseType !== '' && this._settings.responseType) | |||
| $(this._element).trigger($.Event(EVENT_LOADED)) | |||
| } | |||
| _addOverlay() { | |||
| this._parent.append(this._overlay) | |||
| $(this._element).trigger($.Event(EVENT_OVERLAY_ADDED)) | |||
| } | |||
| _removeOverlay() { | |||
| this._parent.find(this._overlay).remove() | |||
| $(this._element).trigger($.Event(EVENT_OVERLAY_REMOVED)) | |||
| } | |||
| // Private | |||
| _init() { | |||
| $(this).find(this._settings.trigger).on('click', () => { | |||
| this.load() | |||
| }) | |||
| if (this._settings.loadOnInit) { | |||
| this.load() | |||
| } | |||
| } | |||
| // Static | |||
| static _jQueryInterface(config) { | |||
| let data = $(this).data(DATA_KEY) | |||
| const _options = $.extend({}, Default, $(this).data()) | |||
| if (!data) { | |||
| data = new CardRefresh($(this), _options) | |||
| $(this).data(DATA_KEY, typeof config === 'string' ? data : config) | |||
| } | |||
| if (typeof config === 'string' && /load/.test(config)) { | |||
| data[config]() | |||
| } else { | |||
| data._init($(this)) | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Data API | |||
| * ==================================================== | |||
| */ | |||
| $(document).on('click', SELECTOR_DATA_REFRESH, function (event) { | |||
| if (event) { | |||
| event.preventDefault() | |||
| } | |||
| CardRefresh._jQueryInterface.call($(this), 'load') | |||
| }) | |||
| $(() => { | |||
| $(SELECTOR_DATA_REFRESH).each(function () { | |||
| CardRefresh._jQueryInterface.call($(this)) | |||
| }) | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = CardRefresh._jQueryInterface | |||
| $.fn[NAME].Constructor = CardRefresh | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return CardRefresh._jQueryInterface | |||
| } | |||
| export default CardRefresh | |||
| @@ -0,0 +1,238 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE CardWidget.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'CardWidget' | |||
| const DATA_KEY = 'lte.cardwidget' | |||
| const EVENT_KEY = `.${DATA_KEY}` | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const EVENT_EXPANDED = `expanded${EVENT_KEY}` | |||
| const EVENT_COLLAPSED = `collapsed${EVENT_KEY}` | |||
| const EVENT_MAXIMIZED = `maximized${EVENT_KEY}` | |||
| const EVENT_MINIMIZED = `minimized${EVENT_KEY}` | |||
| const EVENT_REMOVED = `removed${EVENT_KEY}` | |||
| const CLASS_NAME_CARD = 'card' | |||
| const CLASS_NAME_COLLAPSED = 'collapsed-card' | |||
| const CLASS_NAME_COLLAPSING = 'collapsing-card' | |||
| const CLASS_NAME_EXPANDING = 'expanding-card' | |||
| const CLASS_NAME_WAS_COLLAPSED = 'was-collapsed' | |||
| const CLASS_NAME_MAXIMIZED = 'maximized-card' | |||
| const SELECTOR_DATA_REMOVE = '[data-card-widget="remove"]' | |||
| const SELECTOR_DATA_COLLAPSE = '[data-card-widget="collapse"]' | |||
| const SELECTOR_DATA_MAXIMIZE = '[data-card-widget="maximize"]' | |||
| const SELECTOR_CARD = `.${CLASS_NAME_CARD}` | |||
| const SELECTOR_CARD_HEADER = '.card-header' | |||
| const SELECTOR_CARD_BODY = '.card-body' | |||
| const SELECTOR_CARD_FOOTER = '.card-footer' | |||
| const Default = { | |||
| animationSpeed: 'normal', | |||
| collapseTrigger: SELECTOR_DATA_COLLAPSE, | |||
| removeTrigger: SELECTOR_DATA_REMOVE, | |||
| maximizeTrigger: SELECTOR_DATA_MAXIMIZE, | |||
| collapseIcon: 'fa-minus', | |||
| expandIcon: 'fa-plus', | |||
| maximizeIcon: 'fa-expand', | |||
| minimizeIcon: 'fa-compress' | |||
| } | |||
| class CardWidget { | |||
| constructor(element, settings) { | |||
| this._element = element | |||
| this._parent = element.parents(SELECTOR_CARD).first() | |||
| if (element.hasClass(CLASS_NAME_CARD)) { | |||
| this._parent = element | |||
| } | |||
| this._settings = $.extend({}, Default, settings) | |||
| } | |||
| collapse() { | |||
| this._parent.addClass(CLASS_NAME_COLLAPSING).children(`${SELECTOR_CARD_BODY}, ${SELECTOR_CARD_FOOTER}`) | |||
| .slideUp(this._settings.animationSpeed, () => { | |||
| this._parent.addClass(CLASS_NAME_COLLAPSED).removeClass(CLASS_NAME_COLLAPSING) | |||
| }) | |||
| this._parent.find(`> ${SELECTOR_CARD_HEADER} ${this._settings.collapseTrigger} .${this._settings.collapseIcon}`) | |||
| .addClass(this._settings.expandIcon) | |||
| .removeClass(this._settings.collapseIcon) | |||
| this._element.trigger($.Event(EVENT_COLLAPSED), this._parent) | |||
| } | |||
| expand() { | |||
| this._parent.addClass(CLASS_NAME_EXPANDING).children(`${SELECTOR_CARD_BODY}, ${SELECTOR_CARD_FOOTER}`) | |||
| .slideDown(this._settings.animationSpeed, () => { | |||
| this._parent.removeClass(CLASS_NAME_COLLAPSED).removeClass(CLASS_NAME_EXPANDING) | |||
| }) | |||
| this._parent.find(`> ${SELECTOR_CARD_HEADER} ${this._settings.collapseTrigger} .${this._settings.expandIcon}`) | |||
| .addClass(this._settings.collapseIcon) | |||
| .removeClass(this._settings.expandIcon) | |||
| this._element.trigger($.Event(EVENT_EXPANDED), this._parent) | |||
| } | |||
| remove() { | |||
| this._parent.slideUp() | |||
| this._element.trigger($.Event(EVENT_REMOVED), this._parent) | |||
| } | |||
| toggle() { | |||
| if (this._parent.hasClass(CLASS_NAME_COLLAPSED)) { | |||
| this.expand() | |||
| return | |||
| } | |||
| this.collapse() | |||
| } | |||
| maximize() { | |||
| this._parent.find(`${this._settings.maximizeTrigger} .${this._settings.maximizeIcon}`) | |||
| .addClass(this._settings.minimizeIcon) | |||
| .removeClass(this._settings.maximizeIcon) | |||
| this._parent.css({ | |||
| height: this._parent.height(), | |||
| width: this._parent.width(), | |||
| transition: 'all .15s' | |||
| }).delay(150).queue(function () { | |||
| const $element = $(this) | |||
| $element.addClass(CLASS_NAME_MAXIMIZED) | |||
| $('html').addClass(CLASS_NAME_MAXIMIZED) | |||
| if ($element.hasClass(CLASS_NAME_COLLAPSED)) { | |||
| $element.addClass(CLASS_NAME_WAS_COLLAPSED) | |||
| } | |||
| $element.dequeue() | |||
| }) | |||
| this._element.trigger($.Event(EVENT_MAXIMIZED), this._parent) | |||
| } | |||
| minimize() { | |||
| this._parent.find(`${this._settings.maximizeTrigger} .${this._settings.minimizeIcon}`) | |||
| .addClass(this._settings.maximizeIcon) | |||
| .removeClass(this._settings.minimizeIcon) | |||
| this._parent.css('cssText', `height: ${this._parent[0].style.height} !important; width: ${this._parent[0].style.width} !important; transition: all .15s;` | |||
| ).delay(10).queue(function () { | |||
| const $element = $(this) | |||
| $element.removeClass(CLASS_NAME_MAXIMIZED) | |||
| $('html').removeClass(CLASS_NAME_MAXIMIZED) | |||
| $element.css({ | |||
| height: 'inherit', | |||
| width: 'inherit' | |||
| }) | |||
| if ($element.hasClass(CLASS_NAME_WAS_COLLAPSED)) { | |||
| $element.removeClass(CLASS_NAME_WAS_COLLAPSED) | |||
| } | |||
| $element.dequeue() | |||
| }) | |||
| this._element.trigger($.Event(EVENT_MINIMIZED), this._parent) | |||
| } | |||
| toggleMaximize() { | |||
| if (this._parent.hasClass(CLASS_NAME_MAXIMIZED)) { | |||
| this.minimize() | |||
| return | |||
| } | |||
| this.maximize() | |||
| } | |||
| // Private | |||
| _init(card) { | |||
| this._parent = card | |||
| $(this).find(this._settings.collapseTrigger).click(() => { | |||
| this.toggle() | |||
| }) | |||
| $(this).find(this._settings.maximizeTrigger).click(() => { | |||
| this.toggleMaximize() | |||
| }) | |||
| $(this).find(this._settings.removeTrigger).click(() => { | |||
| this.remove() | |||
| }) | |||
| } | |||
| // Static | |||
| static _jQueryInterface(config) { | |||
| let data = $(this).data(DATA_KEY) | |||
| const _options = $.extend({}, Default, $(this).data()) | |||
| if (!data) { | |||
| data = new CardWidget($(this), _options) | |||
| $(this).data(DATA_KEY, typeof config === 'string' ? data : config) | |||
| } | |||
| if (typeof config === 'string' && /collapse|expand|remove|toggle|maximize|minimize|toggleMaximize/.test(config)) { | |||
| data[config]() | |||
| } else if (typeof config === 'object') { | |||
| data._init($(this)) | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Data API | |||
| * ==================================================== | |||
| */ | |||
| $(document).on('click', SELECTOR_DATA_COLLAPSE, function (event) { | |||
| if (event) { | |||
| event.preventDefault() | |||
| } | |||
| CardWidget._jQueryInterface.call($(this), 'toggle') | |||
| }) | |||
| $(document).on('click', SELECTOR_DATA_REMOVE, function (event) { | |||
| if (event) { | |||
| event.preventDefault() | |||
| } | |||
| CardWidget._jQueryInterface.call($(this), 'remove') | |||
| }) | |||
| $(document).on('click', SELECTOR_DATA_MAXIMIZE, function (event) { | |||
| if (event) { | |||
| event.preventDefault() | |||
| } | |||
| CardWidget._jQueryInterface.call($(this), 'toggleMaximize') | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = CardWidget._jQueryInterface | |||
| $.fn[NAME].Constructor = CardWidget | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return CardWidget._jQueryInterface | |||
| } | |||
| export default CardWidget | |||
| @@ -0,0 +1,322 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE ControlSidebar.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'ControlSidebar' | |||
| const DATA_KEY = 'lte.controlsidebar' | |||
| const EVENT_KEY = `.${DATA_KEY}` | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const EVENT_COLLAPSED = `collapsed${EVENT_KEY}` | |||
| const EVENT_EXPANDED = `expanded${EVENT_KEY}` | |||
| const SELECTOR_CONTROL_SIDEBAR = '.control-sidebar' | |||
| const SELECTOR_CONTROL_SIDEBAR_CONTENT = '.control-sidebar-content' | |||
| const SELECTOR_DATA_TOGGLE = '[data-widget="control-sidebar"]' | |||
| const SELECTOR_HEADER = '.main-header' | |||
| const SELECTOR_FOOTER = '.main-footer' | |||
| const CLASS_NAME_CONTROL_SIDEBAR_ANIMATE = 'control-sidebar-animate' | |||
| const CLASS_NAME_CONTROL_SIDEBAR_OPEN = 'control-sidebar-open' | |||
| const CLASS_NAME_CONTROL_SIDEBAR_SLIDE = 'control-sidebar-slide-open' | |||
| const CLASS_NAME_LAYOUT_FIXED = 'layout-fixed' | |||
| const CLASS_NAME_NAVBAR_FIXED = 'layout-navbar-fixed' | |||
| const CLASS_NAME_NAVBAR_SM_FIXED = 'layout-sm-navbar-fixed' | |||
| const CLASS_NAME_NAVBAR_MD_FIXED = 'layout-md-navbar-fixed' | |||
| const CLASS_NAME_NAVBAR_LG_FIXED = 'layout-lg-navbar-fixed' | |||
| const CLASS_NAME_NAVBAR_XL_FIXED = 'layout-xl-navbar-fixed' | |||
| const CLASS_NAME_FOOTER_FIXED = 'layout-footer-fixed' | |||
| const CLASS_NAME_FOOTER_SM_FIXED = 'layout-sm-footer-fixed' | |||
| const CLASS_NAME_FOOTER_MD_FIXED = 'layout-md-footer-fixed' | |||
| const CLASS_NAME_FOOTER_LG_FIXED = 'layout-lg-footer-fixed' | |||
| const CLASS_NAME_FOOTER_XL_FIXED = 'layout-xl-footer-fixed' | |||
| const Default = { | |||
| controlsidebarSlide: true, | |||
| scrollbarTheme: 'os-theme-light', | |||
| scrollbarAutoHide: 'l', | |||
| target: SELECTOR_CONTROL_SIDEBAR | |||
| } | |||
| /** | |||
| * Class Definition | |||
| * ==================================================== | |||
| */ | |||
| class ControlSidebar { | |||
| constructor(element, config) { | |||
| this._element = element | |||
| this._config = config | |||
| } | |||
| // Public | |||
| collapse() { | |||
| const $body = $('body') | |||
| const $html = $('html') | |||
| const { target } = this._config | |||
| // Show the control sidebar | |||
| if (this._config.controlsidebarSlide) { | |||
| $html.addClass(CLASS_NAME_CONTROL_SIDEBAR_ANIMATE) | |||
| $body.removeClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE).delay(300).queue(function () { | |||
| $(target).hide() | |||
| $html.removeClass(CLASS_NAME_CONTROL_SIDEBAR_ANIMATE) | |||
| $(this).dequeue() | |||
| }) | |||
| } else { | |||
| $body.removeClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) | |||
| } | |||
| $(this._element).trigger($.Event(EVENT_COLLAPSED)) | |||
| } | |||
| show() { | |||
| const $body = $('body') | |||
| const $html = $('html') | |||
| // Collapse the control sidebar | |||
| if (this._config.controlsidebarSlide) { | |||
| $html.addClass(CLASS_NAME_CONTROL_SIDEBAR_ANIMATE) | |||
| $(this._config.target).show().delay(10).queue(function () { | |||
| $body.addClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE).delay(300).queue(function () { | |||
| $html.removeClass(CLASS_NAME_CONTROL_SIDEBAR_ANIMATE) | |||
| $(this).dequeue() | |||
| }) | |||
| $(this).dequeue() | |||
| }) | |||
| } else { | |||
| $body.addClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) | |||
| } | |||
| this._fixHeight() | |||
| this._fixScrollHeight() | |||
| $(this._element).trigger($.Event(EVENT_EXPANDED)) | |||
| } | |||
| toggle() { | |||
| const $body = $('body') | |||
| const shouldClose = $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) || | |||
| $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE) | |||
| if (shouldClose) { | |||
| // Close the control sidebar | |||
| this.collapse() | |||
| } else { | |||
| // Open the control sidebar | |||
| this.show() | |||
| } | |||
| } | |||
| // Private | |||
| _init() { | |||
| const $body = $('body') | |||
| const shouldNotHideAll = $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) || | |||
| $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE) | |||
| if (shouldNotHideAll) { | |||
| $(SELECTOR_CONTROL_SIDEBAR).not(this._config.target).hide() | |||
| $(this._config.target).css('display', 'block') | |||
| } else { | |||
| $(SELECTOR_CONTROL_SIDEBAR).hide() | |||
| } | |||
| this._fixHeight() | |||
| this._fixScrollHeight() | |||
| $(window).resize(() => { | |||
| this._fixHeight() | |||
| this._fixScrollHeight() | |||
| }) | |||
| $(window).scroll(() => { | |||
| const $body = $('body') | |||
| const shouldFixHeight = $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) || | |||
| $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE) | |||
| if (shouldFixHeight) { | |||
| this._fixScrollHeight() | |||
| } | |||
| }) | |||
| } | |||
| _isNavbarFixed() { | |||
| const $body = $('body') | |||
| return ( | |||
| $body.hasClass(CLASS_NAME_NAVBAR_FIXED) || | |||
| $body.hasClass(CLASS_NAME_NAVBAR_SM_FIXED) || | |||
| $body.hasClass(CLASS_NAME_NAVBAR_MD_FIXED) || | |||
| $body.hasClass(CLASS_NAME_NAVBAR_LG_FIXED) || | |||
| $body.hasClass(CLASS_NAME_NAVBAR_XL_FIXED) | |||
| ) | |||
| } | |||
| _isFooterFixed() { | |||
| const $body = $('body') | |||
| return ( | |||
| $body.hasClass(CLASS_NAME_FOOTER_FIXED) || | |||
| $body.hasClass(CLASS_NAME_FOOTER_SM_FIXED) || | |||
| $body.hasClass(CLASS_NAME_FOOTER_MD_FIXED) || | |||
| $body.hasClass(CLASS_NAME_FOOTER_LG_FIXED) || | |||
| $body.hasClass(CLASS_NAME_FOOTER_XL_FIXED) | |||
| ) | |||
| } | |||
| _fixScrollHeight() { | |||
| const $body = $('body') | |||
| const $controlSidebar = $(this._config.target) | |||
| if (!$body.hasClass(CLASS_NAME_LAYOUT_FIXED)) { | |||
| return | |||
| } | |||
| const heights = { | |||
| scroll: $(document).height(), | |||
| window: $(window).height(), | |||
| header: $(SELECTOR_HEADER).outerHeight(), | |||
| footer: $(SELECTOR_FOOTER).outerHeight() | |||
| } | |||
| const positions = { | |||
| bottom: Math.abs((heights.window + $(window).scrollTop()) - heights.scroll), | |||
| top: $(window).scrollTop() | |||
| } | |||
| const navbarFixed = this._isNavbarFixed() && $(SELECTOR_HEADER).css('position') === 'fixed' | |||
| const footerFixed = this._isFooterFixed() && $(SELECTOR_FOOTER).css('position') === 'fixed' | |||
| const $controlsidebarContent = $(`${this._config.target}, ${this._config.target} ${SELECTOR_CONTROL_SIDEBAR_CONTENT}`) | |||
| if (positions.top === 0 && positions.bottom === 0) { | |||
| $controlSidebar.css({ | |||
| bottom: heights.footer, | |||
| top: heights.header | |||
| }) | |||
| $controlsidebarContent.css('height', heights.window - (heights.header + heights.footer)) | |||
| } else if (positions.bottom <= heights.footer) { | |||
| if (footerFixed === false) { | |||
| const top = heights.header - positions.top | |||
| $controlSidebar.css('bottom', heights.footer - positions.bottom).css('top', top >= 0 ? top : 0) | |||
| $controlsidebarContent.css('height', heights.window - (heights.footer - positions.bottom)) | |||
| } else { | |||
| $controlSidebar.css('bottom', heights.footer) | |||
| } | |||
| } else if (positions.top <= heights.header) { | |||
| if (navbarFixed === false) { | |||
| $controlSidebar.css('top', heights.header - positions.top) | |||
| $controlsidebarContent.css('height', heights.window - (heights.header - positions.top)) | |||
| } else { | |||
| $controlSidebar.css('top', heights.header) | |||
| } | |||
| } else if (navbarFixed === false) { | |||
| $controlSidebar.css('top', 0) | |||
| $controlsidebarContent.css('height', heights.window) | |||
| } else { | |||
| $controlSidebar.css('top', heights.header) | |||
| } | |||
| if (footerFixed && navbarFixed) { | |||
| $controlsidebarContent.css('height', '100%') | |||
| $controlSidebar.css('height', '') | |||
| } else if (footerFixed || navbarFixed) { | |||
| $controlsidebarContent.css('height', '100%') | |||
| $controlsidebarContent.css('height', '') | |||
| } | |||
| } | |||
| _fixHeight() { | |||
| const $body = $('body') | |||
| const $controlSidebar = $(`${this._config.target} ${SELECTOR_CONTROL_SIDEBAR_CONTENT}`) | |||
| if (!$body.hasClass(CLASS_NAME_LAYOUT_FIXED)) { | |||
| $controlSidebar.attr('style', '') | |||
| return | |||
| } | |||
| const heights = { | |||
| window: $(window).height(), | |||
| header: $(SELECTOR_HEADER).outerHeight(), | |||
| footer: $(SELECTOR_FOOTER).outerHeight() | |||
| } | |||
| let sidebarHeight = heights.window - heights.header | |||
| if (this._isFooterFixed() && $(SELECTOR_FOOTER).css('position') === 'fixed') { | |||
| sidebarHeight = heights.window - heights.header - heights.footer | |||
| } | |||
| $controlSidebar.css('height', sidebarHeight) | |||
| if (typeof $.fn.overlayScrollbars !== 'undefined') { | |||
| $controlSidebar.overlayScrollbars({ | |||
| className: this._config.scrollbarTheme, | |||
| sizeAutoCapable: true, | |||
| scrollbars: { | |||
| autoHide: this._config.scrollbarAutoHide, | |||
| clickScrolling: true | |||
| } | |||
| }) | |||
| } | |||
| } | |||
| // Static | |||
| static _jQueryInterface(operation) { | |||
| return this.each(function () { | |||
| let data = $(this).data(DATA_KEY) | |||
| const _options = $.extend({}, Default, $(this).data()) | |||
| if (!data) { | |||
| data = new ControlSidebar(this, _options) | |||
| $(this).data(DATA_KEY, data) | |||
| } | |||
| if (data[operation] === 'undefined') { | |||
| throw new Error(`${operation} is not a function`) | |||
| } | |||
| data[operation]() | |||
| }) | |||
| } | |||
| } | |||
| /** | |||
| * | |||
| * Data Api implementation | |||
| * ==================================================== | |||
| */ | |||
| $(document).on('click', SELECTOR_DATA_TOGGLE, function (event) { | |||
| event.preventDefault() | |||
| ControlSidebar._jQueryInterface.call($(this), 'toggle') | |||
| }) | |||
| $(document).ready(() => { | |||
| ControlSidebar._jQueryInterface.call($(SELECTOR_DATA_TOGGLE), '_init') | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = ControlSidebar._jQueryInterface | |||
| $.fn[NAME].Constructor = ControlSidebar | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return ControlSidebar._jQueryInterface | |||
| } | |||
| export default ControlSidebar | |||
| @@ -0,0 +1,84 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE DirectChat.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'DirectChat' | |||
| const DATA_KEY = 'lte.directchat' | |||
| const EVENT_KEY = `.${DATA_KEY}` | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const EVENT_TOGGLED = `toggled${EVENT_KEY}` | |||
| const SELECTOR_DATA_TOGGLE = '[data-widget="chat-pane-toggle"]' | |||
| const SELECTOR_DIRECT_CHAT = '.direct-chat' | |||
| const CLASS_NAME_DIRECT_CHAT_OPEN = 'direct-chat-contacts-open' | |||
| /** | |||
| * Class Definition | |||
| * ==================================================== | |||
| */ | |||
| class DirectChat { | |||
| constructor(element) { | |||
| this._element = element | |||
| } | |||
| toggle() { | |||
| $(this._element).parents(SELECTOR_DIRECT_CHAT).first().toggleClass(CLASS_NAME_DIRECT_CHAT_OPEN) | |||
| $(this._element).trigger($.Event(EVENT_TOGGLED)) | |||
| } | |||
| // Static | |||
| static _jQueryInterface(config) { | |||
| return this.each(function () { | |||
| let data = $(this).data(DATA_KEY) | |||
| if (!data) { | |||
| data = new DirectChat($(this)) | |||
| $(this).data(DATA_KEY, data) | |||
| } | |||
| data[config]() | |||
| }) | |||
| } | |||
| } | |||
| /** | |||
| * | |||
| * Data Api implementation | |||
| * ==================================================== | |||
| */ | |||
| $(document).on('click', SELECTOR_DATA_TOGGLE, function (event) { | |||
| if (event) { | |||
| event.preventDefault() | |||
| } | |||
| DirectChat._jQueryInterface.call($(this), 'toggle') | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = DirectChat._jQueryInterface | |||
| $.fn[NAME].Constructor = DirectChat | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return DirectChat._jQueryInterface | |||
| } | |||
| export default DirectChat | |||
| @@ -0,0 +1,146 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE Dropdown.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'Dropdown' | |||
| const DATA_KEY = 'lte.dropdown' | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const SELECTOR_NAVBAR = '.navbar' | |||
| const SELECTOR_DROPDOWN_MENU = '.dropdown-menu' | |||
| const SELECTOR_DROPDOWN_MENU_ACTIVE = '.dropdown-menu.show' | |||
| const SELECTOR_DROPDOWN_TOGGLE = '[data-toggle="dropdown"]' | |||
| const CLASS_NAME_DROPDOWN_RIGHT = 'dropdown-menu-right' | |||
| const CLASS_NAME_DROPDOWN_SUBMENU = 'dropdown-submenu' | |||
| // TODO: this is unused; should be removed along with the extend? | |||
| const Default = {} | |||
| /** | |||
| * Class Definition | |||
| * ==================================================== | |||
| */ | |||
| class Dropdown { | |||
| constructor(element, config) { | |||
| this._config = config | |||
| this._element = element | |||
| } | |||
| // Public | |||
| toggleSubmenu() { | |||
| this._element.siblings().show().toggleClass('show') | |||
| if (!this._element.next().hasClass('show')) { | |||
| this._element.parents(SELECTOR_DROPDOWN_MENU).first().find('.show').removeClass('show').hide() | |||
| } | |||
| this._element.parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', () => { | |||
| $('.dropdown-submenu .show').removeClass('show').hide() | |||
| }) | |||
| } | |||
| fixPosition() { | |||
| const $element = $(SELECTOR_DROPDOWN_MENU_ACTIVE) | |||
| if ($element.length === 0) { | |||
| return | |||
| } | |||
| if ($element.hasClass(CLASS_NAME_DROPDOWN_RIGHT)) { | |||
| $element.css({ | |||
| left: 'inherit', | |||
| right: 0 | |||
| }) | |||
| } else { | |||
| $element.css({ | |||
| left: 0, | |||
| right: 'inherit' | |||
| }) | |||
| } | |||
| const offset = $element.offset() | |||
| const width = $element.width() | |||
| const visiblePart = $(window).width() - offset.left | |||
| if (offset.left < 0) { | |||
| $element.css({ | |||
| left: 'inherit', | |||
| right: offset.left - 5 | |||
| }) | |||
| } else if (visiblePart < width) { | |||
| $element.css({ | |||
| left: 'inherit', | |||
| right: 0 | |||
| }) | |||
| } | |||
| } | |||
| // Static | |||
| static _jQueryInterface(config) { | |||
| return this.each(function () { | |||
| let data = $(this).data(DATA_KEY) | |||
| const _config = $.extend({}, Default, $(this).data()) | |||
| if (!data) { | |||
| data = new Dropdown($(this), _config) | |||
| $(this).data(DATA_KEY, data) | |||
| } | |||
| if (config === 'toggleSubmenu' || config === 'fixPosition') { | |||
| data[config]() | |||
| } | |||
| }) | |||
| } | |||
| } | |||
| /** | |||
| * Data API | |||
| * ==================================================== | |||
| */ | |||
| $(`${SELECTOR_DROPDOWN_MENU} ${SELECTOR_DROPDOWN_TOGGLE}`).on('click', function (event) { | |||
| event.preventDefault() | |||
| event.stopPropagation() | |||
| Dropdown._jQueryInterface.call($(this), 'toggleSubmenu') | |||
| }) | |||
| $(`${SELECTOR_NAVBAR} ${SELECTOR_DROPDOWN_TOGGLE}`).on('click', event => { | |||
| event.preventDefault() | |||
| if ($(event.target).parent().hasClass(CLASS_NAME_DROPDOWN_SUBMENU)) { | |||
| return | |||
| } | |||
| setTimeout(function () { | |||
| Dropdown._jQueryInterface.call($(this), 'fixPosition') | |||
| }, 1) | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = Dropdown._jQueryInterface | |||
| $.fn[NAME].Constructor = Dropdown | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return Dropdown._jQueryInterface | |||
| } | |||
| export default Dropdown | |||
| @@ -0,0 +1,116 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE ExpandableTable.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'ExpandableTable' | |||
| const DATA_KEY = 'lte.expandableTable' | |||
| const EVENT_KEY = `.${DATA_KEY}` | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const EVENT_EXPANDED = `expanded${EVENT_KEY}` | |||
| const EVENT_COLLAPSED = `collapsed${EVENT_KEY}` | |||
| const SELECTOR_TABLE = '.expandable-table' | |||
| const SELECTOR_EXPANDABLE_BODY = '.expandable-body' | |||
| const SELECTOR_DATA_TOGGLE = '[data-widget="expandable-table"]' | |||
| const SELECTOR_ARIA_ATTR = 'aria-expanded' | |||
| /** | |||
| * Class Definition | |||
| * ==================================================== | |||
| */ | |||
| class ExpandableTable { | |||
| constructor(element, options) { | |||
| this._options = options | |||
| this._element = element | |||
| } | |||
| // Public | |||
| init() { | |||
| $(SELECTOR_DATA_TOGGLE).each((_, $header) => { | |||
| const $type = $($header).attr(SELECTOR_ARIA_ATTR) | |||
| const $body = $($header).next(SELECTOR_EXPANDABLE_BODY).children().first().children() | |||
| if ($type === 'true') { | |||
| $body.show() | |||
| } else if ($type === 'false') { | |||
| $body.hide() | |||
| $body.parent().parent().addClass('d-none') | |||
| } | |||
| }) | |||
| } | |||
| toggleRow() { | |||
| const $element = this._element | |||
| const time = 500 | |||
| const $type = $element.attr(SELECTOR_ARIA_ATTR) | |||
| const $body = $element.next(SELECTOR_EXPANDABLE_BODY).children().first().children() | |||
| $body.stop() | |||
| if ($type === 'true') { | |||
| $body.slideUp(time, () => { | |||
| $element.next(SELECTOR_EXPANDABLE_BODY).addClass('d-none') | |||
| }) | |||
| $element.attr(SELECTOR_ARIA_ATTR, 'false') | |||
| $element.trigger($.Event(EVENT_COLLAPSED)) | |||
| } else if ($type === 'false') { | |||
| $element.next(SELECTOR_EXPANDABLE_BODY).removeClass('d-none') | |||
| $body.slideDown(time) | |||
| $element.attr(SELECTOR_ARIA_ATTR, 'true') | |||
| $element.trigger($.Event(EVENT_EXPANDED)) | |||
| } | |||
| } | |||
| // Static | |||
| static _jQueryInterface(operation) { | |||
| return this.each(function () { | |||
| let data = $(this).data(DATA_KEY) | |||
| if (!data) { | |||
| data = new ExpandableTable($(this)) | |||
| $(this).data(DATA_KEY, data) | |||
| } | |||
| if (typeof operation === 'string' && /init|toggleRow/.test(operation)) { | |||
| data[operation]() | |||
| } | |||
| }) | |||
| } | |||
| } | |||
| /** | |||
| * Data API | |||
| * ==================================================== | |||
| */ | |||
| $(SELECTOR_TABLE).ready(function () { | |||
| ExpandableTable._jQueryInterface.call($(this), 'init') | |||
| }) | |||
| $(document).on('click', SELECTOR_DATA_TOGGLE, function () { | |||
| ExpandableTable._jQueryInterface.call($(this), 'toggleRow') | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = ExpandableTable._jQueryInterface | |||
| $.fn[NAME].Constructor = ExpandableTable | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return ExpandableTable._jQueryInterface | |||
| } | |||
| export default ExpandableTable | |||
| @@ -0,0 +1,117 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE Fullscreen.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'Fullscreen' | |||
| const DATA_KEY = 'lte.fullscreen' | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const SELECTOR_DATA_WIDGET = '[data-widget="fullscreen"]' | |||
| const SELECTOR_ICON = `${SELECTOR_DATA_WIDGET} i` | |||
| const Default = { | |||
| minimizeIcon: 'fa-compress-arrows-alt', | |||
| maximizeIcon: 'fa-expand-arrows-alt' | |||
| } | |||
| /** | |||
| * Class Definition | |||
| * ==================================================== | |||
| */ | |||
| class Fullscreen { | |||
| constructor(_element, _options) { | |||
| this.element = _element | |||
| this.options = $.extend({}, Default, _options) | |||
| } | |||
| // Public | |||
| toggle() { | |||
| if (document.fullscreenElement || | |||
| document.mozFullScreenElement || | |||
| document.webkitFullscreenElement || | |||
| document.msFullscreenElement) { | |||
| this.windowed() | |||
| } else { | |||
| this.fullscreen() | |||
| } | |||
| } | |||
| fullscreen() { | |||
| if (document.documentElement.requestFullscreen) { | |||
| document.documentElement.requestFullscreen() | |||
| } else if (document.documentElement.webkitRequestFullscreen) { | |||
| document.documentElement.webkitRequestFullscreen() | |||
| } else if (document.documentElement.msRequestFullscreen) { | |||
| document.documentElement.msRequestFullscreen() | |||
| } | |||
| $(SELECTOR_ICON).removeClass(this.options.maximizeIcon).addClass(this.options.minimizeIcon) | |||
| } | |||
| windowed() { | |||
| if (document.exitFullscreen) { | |||
| document.exitFullscreen() | |||
| } else if (document.webkitExitFullscreen) { | |||
| document.webkitExitFullscreen() | |||
| } else if (document.msExitFullscreen) { | |||
| document.msExitFullscreen() | |||
| } | |||
| $(SELECTOR_ICON).removeClass(this.options.minimizeIcon).addClass(this.options.maximizeIcon) | |||
| } | |||
| // Static | |||
| static _jQueryInterface(config) { | |||
| let data = $(this).data(DATA_KEY) | |||
| if (!data) { | |||
| data = $(this).data() | |||
| } | |||
| const _options = $.extend({}, Default, typeof config === 'object' ? config : data) | |||
| const plugin = new Fullscreen($(this), _options) | |||
| $(this).data(DATA_KEY, typeof config === 'object' ? config : data) | |||
| if (typeof config === 'string' && /toggle|fullscreen|windowed/.test(config)) { | |||
| plugin[config]() | |||
| } else { | |||
| plugin.init() | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Data API | |||
| * ==================================================== | |||
| */ | |||
| $(document).on('click', SELECTOR_DATA_WIDGET, function () { | |||
| Fullscreen._jQueryInterface.call($(this), 'toggle') | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = Fullscreen._jQueryInterface | |||
| $.fn[NAME].Constructor = Fullscreen | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return Fullscreen._jQueryInterface | |||
| } | |||
| export default Fullscreen | |||
| @@ -0,0 +1,413 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE IFrame.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'IFrame' | |||
| const DATA_KEY = 'lte.iframe' | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const SELECTOR_DATA_TOGGLE = '[data-widget="iframe"]' | |||
| const SELECTOR_DATA_TOGGLE_CLOSE = '[data-widget="iframe-close"]' | |||
| const SELECTOR_DATA_TOGGLE_SCROLL_LEFT = '[data-widget="iframe-scrollleft"]' | |||
| const SELECTOR_DATA_TOGGLE_SCROLL_RIGHT = '[data-widget="iframe-scrollright"]' | |||
| const SELECTOR_DATA_TOGGLE_FULLSCREEN = '[data-widget="iframe-fullscreen"]' | |||
| const SELECTOR_CONTENT_WRAPPER = '.content-wrapper' | |||
| const SELECTOR_CONTENT_IFRAME = `${SELECTOR_CONTENT_WRAPPER} iframe` | |||
| const SELECTOR_TAB_NAV = `${SELECTOR_DATA_TOGGLE}.iframe-mode .nav` | |||
| const SELECTOR_TAB_NAVBAR_NAV = `${SELECTOR_DATA_TOGGLE}.iframe-mode .navbar-nav` | |||
| const SELECTOR_TAB_NAVBAR_NAV_ITEM = `${SELECTOR_TAB_NAVBAR_NAV} .nav-item` | |||
| const SELECTOR_TAB_NAVBAR_NAV_LINK = `${SELECTOR_TAB_NAVBAR_NAV} .nav-link` | |||
| const SELECTOR_TAB_CONTENT = `${SELECTOR_DATA_TOGGLE}.iframe-mode .tab-content` | |||
| const SELECTOR_TAB_EMPTY = `${SELECTOR_TAB_CONTENT} .tab-empty` | |||
| const SELECTOR_TAB_LOADING = `${SELECTOR_TAB_CONTENT} .tab-loading` | |||
| const SELECTOR_TAB_PANE = `${SELECTOR_TAB_CONTENT} .tab-pane` | |||
| const SELECTOR_SIDEBAR_MENU_ITEM = '.main-sidebar .nav-item > a.nav-link' | |||
| const SELECTOR_SIDEBAR_SEARCH_ITEM = '.sidebar-search-results .list-group-item' | |||
| const SELECTOR_HEADER_MENU_ITEM = '.main-header .nav-item a.nav-link' | |||
| const SELECTOR_HEADER_DROPDOWN_ITEM = '.main-header a.dropdown-item' | |||
| const CLASS_NAME_IFRAME_MODE = 'iframe-mode' | |||
| const CLASS_NAME_FULLSCREEN_MODE = 'iframe-mode-fullscreen' | |||
| const Default = { | |||
| onTabClick(item) { | |||
| return item | |||
| }, | |||
| onTabChanged(item) { | |||
| return item | |||
| }, | |||
| onTabCreated(item) { | |||
| return item | |||
| }, | |||
| autoIframeMode: true, | |||
| autoItemActive: true, | |||
| autoShowNewTab: true, | |||
| allowDuplicates: false, | |||
| loadingScreen: true, | |||
| useNavbarItems: true, | |||
| scrollOffset: 40, | |||
| scrollBehaviorSwap: false, | |||
| iconMaximize: 'fa-expand', | |||
| iconMinimize: 'fa-compress' | |||
| } | |||
| /** | |||
| * Class Definition | |||
| * ==================================================== | |||
| */ | |||
| class IFrame { | |||
| constructor(element, config) { | |||
| this._config = config | |||
| this._element = element | |||
| this._init() | |||
| } | |||
| // Public | |||
| onTabClick(item) { | |||
| this._config.onTabClick(item) | |||
| } | |||
| onTabChanged(item) { | |||
| this._config.onTabChanged(item) | |||
| } | |||
| onTabCreated(item) { | |||
| this._config.onTabCreated(item) | |||
| } | |||
| createTab(title, link, uniqueName, autoOpen) { | |||
| let tabId = `panel-${uniqueName}` | |||
| let navId = `tab-${uniqueName}` | |||
| if (this._config.allowDuplicates) { | |||
| tabId += `-${Math.floor(Math.random() * 1000)}` | |||
| navId += `-${Math.floor(Math.random() * 1000)}` | |||
| } | |||
| const newNavItem = `<li class="nav-item" role="presentation"><a href="#" class="btn-iframe-close" data-widget="iframe-close" data-type="only-this"><i class="fas fa-times"></i></a><a class="nav-link" data-toggle="row" id="${navId}" href="#${tabId}" role="tab" aria-controls="${tabId}" aria-selected="false">${title}</a></li>` | |||
| $(SELECTOR_TAB_NAVBAR_NAV).append(unescape(escape(newNavItem))) | |||
| const newTabItem = `<div class="tab-pane fade" id="${tabId}" role="tabpanel" aria-labelledby="${navId}"><iframe src="${link}"></iframe></div>` | |||
| $(SELECTOR_TAB_CONTENT).append(unescape(escape(newTabItem))) | |||
| if (autoOpen) { | |||
| if (this._config.loadingScreen) { | |||
| const $loadingScreen = $(SELECTOR_TAB_LOADING) | |||
| $loadingScreen.fadeIn() | |||
| $(`${tabId} iframe`).ready(() => { | |||
| if (typeof this._config.loadingScreen === 'number') { | |||
| this.switchTab(`#${navId}`) | |||
| setTimeout(() => { | |||
| $loadingScreen.fadeOut() | |||
| }, this._config.loadingScreen) | |||
| } else { | |||
| this.switchTab(`#${navId}`) | |||
| $loadingScreen.fadeOut() | |||
| } | |||
| }) | |||
| } else { | |||
| this.switchTab(`#${navId}`) | |||
| } | |||
| } | |||
| this.onTabCreated($(`#${navId}`)) | |||
| } | |||
| openTabSidebar(item, autoOpen = this._config.autoShowNewTab) { | |||
| let $item = $(item).clone() | |||
| if ($item.attr('href') === undefined) { | |||
| $item = $(item).parent('a').clone() | |||
| } | |||
| $item.find('.right, .search-path').remove() | |||
| let title = $item.find('p').text() | |||
| if (title === '') { | |||
| title = $item.text() | |||
| } | |||
| const link = $item.attr('href') | |||
| if (link === '#' || link === '' || link === undefined) { | |||
| return | |||
| } | |||
| const uniqueName = link.replace('./', '').replace(/["&'./:=?[\]]/gi, '-').replace(/(--)/gi, '') | |||
| const navId = `tab-${uniqueName}` | |||
| if (!this._config.allowDuplicates && $(`#${navId}`).length > 0) { | |||
| return this.switchTab(`#${navId}`) | |||
| } | |||
| if ((!this._config.allowDuplicates && $(`#${navId}`).length === 0) || this._config.allowDuplicates) { | |||
| this.createTab(title, link, uniqueName, autoOpen) | |||
| } | |||
| } | |||
| switchTab(item) { | |||
| const $item = $(item) | |||
| const tabId = $item.attr('href') | |||
| $(SELECTOR_TAB_EMPTY).hide() | |||
| $(`${SELECTOR_TAB_NAVBAR_NAV} .active`).tab('dispose').removeClass('active') | |||
| this._fixHeight() | |||
| $item.tab('show') | |||
| $item.parents('li').addClass('active') | |||
| this.onTabChanged($item) | |||
| if (this._config.autoItemActive) { | |||
| this._setItemActive($(`${tabId} iframe`).attr('src')) | |||
| } | |||
| } | |||
| removeActiveTab(type, element) { | |||
| if (type == 'all') { | |||
| $(SELECTOR_TAB_NAVBAR_NAV_ITEM).remove() | |||
| $(SELECTOR_TAB_PANE).remove() | |||
| $(SELECTOR_TAB_EMPTY).show() | |||
| } else if (type == 'all-other') { | |||
| $(`${SELECTOR_TAB_NAVBAR_NAV_ITEM}:not(.active)`).remove() | |||
| $(`${SELECTOR_TAB_PANE}:not(.active)`).remove() | |||
| } else if (type == 'only-this') { | |||
| const $navClose = $(element) | |||
| const $navItem = $navClose.parent('.nav-item') | |||
| const $navItemParent = $navItem.parent() | |||
| const navItemIndex = $navItem.index() | |||
| const tabId = $navClose.siblings('.nav-link').attr('aria-controls') | |||
| $navItem.remove() | |||
| $(`#${tabId}`).remove() | |||
| if ($(SELECTOR_TAB_CONTENT).children().length == $(`${SELECTOR_TAB_EMPTY}, ${SELECTOR_TAB_LOADING}`).length) { | |||
| $(SELECTOR_TAB_EMPTY).show() | |||
| } else { | |||
| const prevNavItemIndex = navItemIndex - 1 | |||
| this.switchTab($navItemParent.children().eq(prevNavItemIndex).find('a.nav-link')) | |||
| } | |||
| } else { | |||
| const $navItem = $(`${SELECTOR_TAB_NAVBAR_NAV_ITEM}.active`) | |||
| const $navItemParent = $navItem.parent() | |||
| const navItemIndex = $navItem.index() | |||
| $navItem.remove() | |||
| $(`${SELECTOR_TAB_PANE}.active`).remove() | |||
| if ($(SELECTOR_TAB_CONTENT).children().length == $(`${SELECTOR_TAB_EMPTY}, ${SELECTOR_TAB_LOADING}`).length) { | |||
| $(SELECTOR_TAB_EMPTY).show() | |||
| } else { | |||
| const prevNavItemIndex = navItemIndex - 1 | |||
| this.switchTab($navItemParent.children().eq(prevNavItemIndex).find('a.nav-link')) | |||
| } | |||
| } | |||
| } | |||
| toggleFullscreen() { | |||
| if ($('body').hasClass(CLASS_NAME_FULLSCREEN_MODE)) { | |||
| $(`${SELECTOR_DATA_TOGGLE_FULLSCREEN} i`).removeClass(this._config.iconMinimize).addClass(this._config.iconMaximize) | |||
| $('body').removeClass(CLASS_NAME_FULLSCREEN_MODE) | |||
| $(`${SELECTOR_TAB_EMPTY}, ${SELECTOR_TAB_LOADING}`).height('auto') | |||
| $(SELECTOR_CONTENT_WRAPPER).height('auto') | |||
| $(SELECTOR_CONTENT_IFRAME).height('auto') | |||
| } else { | |||
| $(`${SELECTOR_DATA_TOGGLE_FULLSCREEN} i`).removeClass(this._config.iconMaximize).addClass(this._config.iconMinimize) | |||
| $('body').addClass(CLASS_NAME_FULLSCREEN_MODE) | |||
| } | |||
| $(window).trigger('resize') | |||
| this._fixHeight(true) | |||
| } | |||
| // Private | |||
| _init() { | |||
| if (window.frameElement && this._config.autoIframeMode) { | |||
| $('body').addClass(CLASS_NAME_IFRAME_MODE) | |||
| } else if ($(SELECTOR_CONTENT_WRAPPER).hasClass(CLASS_NAME_IFRAME_MODE)) { | |||
| if ($(SELECTOR_TAB_CONTENT).children().length > 2) { | |||
| const $el = $(`${SELECTOR_TAB_PANE}:first-child`) | |||
| $el.show() | |||
| this._setItemActive($el.find('iframe').attr('src')) | |||
| } | |||
| this._setupListeners() | |||
| this._fixHeight(true) | |||
| } | |||
| } | |||
| _navScroll(offset) { | |||
| const leftPos = $(SELECTOR_TAB_NAVBAR_NAV).scrollLeft() | |||
| $(SELECTOR_TAB_NAVBAR_NAV).animate({ scrollLeft: (leftPos + offset) }, 250, 'linear') | |||
| } | |||
| _setupListeners() { | |||
| $(window).on('resize', () => { | |||
| setTimeout(() => { | |||
| this._fixHeight() | |||
| }, 1) | |||
| }) | |||
| $(document).on('click', `${SELECTOR_SIDEBAR_MENU_ITEM}, ${SELECTOR_SIDEBAR_SEARCH_ITEM}`, e => { | |||
| e.preventDefault() | |||
| this.openTabSidebar(e.target) | |||
| }) | |||
| if (this._config.useNavbarItems) { | |||
| $(document).on('click', `${SELECTOR_HEADER_MENU_ITEM}, ${SELECTOR_HEADER_DROPDOWN_ITEM}`, e => { | |||
| e.preventDefault() | |||
| this.openTabSidebar(e.target) | |||
| }) | |||
| } | |||
| $(document).on('click', SELECTOR_TAB_NAVBAR_NAV_LINK, e => { | |||
| e.preventDefault() | |||
| this.onTabClick(e.target) | |||
| this.switchTab(e.target) | |||
| }) | |||
| $(document).on('click', SELECTOR_TAB_NAVBAR_NAV_LINK, e => { | |||
| e.preventDefault() | |||
| this.onTabClick(e.target) | |||
| this.switchTab(e.target) | |||
| }) | |||
| $(document).on('click', SELECTOR_DATA_TOGGLE_CLOSE, e => { | |||
| e.preventDefault() | |||
| let { target } = e | |||
| if (target.nodeName == 'I') { | |||
| target = e.target.offsetParent | |||
| } | |||
| this.removeActiveTab(target.attributes['data-type'] ? target.attributes['data-type'].nodeValue : null, target) | |||
| }) | |||
| $(document).on('click', SELECTOR_DATA_TOGGLE_FULLSCREEN, e => { | |||
| e.preventDefault() | |||
| this.toggleFullscreen() | |||
| }) | |||
| let mousedown = false | |||
| let mousedownInterval = null | |||
| $(document).on('mousedown', SELECTOR_DATA_TOGGLE_SCROLL_LEFT, e => { | |||
| e.preventDefault() | |||
| clearInterval(mousedownInterval) | |||
| let { scrollOffset } = this._config | |||
| if (!this._config.scrollBehaviorSwap) { | |||
| scrollOffset = -scrollOffset | |||
| } | |||
| mousedown = true | |||
| this._navScroll(scrollOffset) | |||
| mousedownInterval = setInterval(() => { | |||
| this._navScroll(scrollOffset) | |||
| }, 250) | |||
| }) | |||
| $(document).on('mousedown', SELECTOR_DATA_TOGGLE_SCROLL_RIGHT, e => { | |||
| e.preventDefault() | |||
| clearInterval(mousedownInterval) | |||
| let { scrollOffset } = this._config | |||
| if (this._config.scrollBehaviorSwap) { | |||
| scrollOffset = -scrollOffset | |||
| } | |||
| mousedown = true | |||
| this._navScroll(scrollOffset) | |||
| mousedownInterval = setInterval(() => { | |||
| this._navScroll(scrollOffset) | |||
| }, 250) | |||
| }) | |||
| $(document).on('mouseup', () => { | |||
| if (mousedown) { | |||
| mousedown = false | |||
| clearInterval(mousedownInterval) | |||
| mousedownInterval = null | |||
| } | |||
| }) | |||
| } | |||
| _setItemActive(href) { | |||
| $(`${SELECTOR_SIDEBAR_MENU_ITEM}, ${SELECTOR_HEADER_DROPDOWN_ITEM}`).removeClass('active') | |||
| $(SELECTOR_HEADER_MENU_ITEM).parent().removeClass('active') | |||
| const $headerMenuItem = $(`${SELECTOR_HEADER_MENU_ITEM}[href$="${href}"]`) | |||
| const $headerDropdownItem = $(`${SELECTOR_HEADER_DROPDOWN_ITEM}[href$="${href}"]`) | |||
| const $sidebarMenuItem = $(`${SELECTOR_SIDEBAR_MENU_ITEM}[href$="${href}"]`) | |||
| $headerMenuItem.each((i, e) => { | |||
| $(e).parent().addClass('active') | |||
| }) | |||
| $headerDropdownItem.each((i, e) => { | |||
| $(e).addClass('active') | |||
| }) | |||
| $sidebarMenuItem.each((i, e) => { | |||
| $(e).addClass('active') | |||
| $(e).parents('.nav-treeview').prevAll('.nav-link').addClass('active') | |||
| }) | |||
| } | |||
| _fixHeight(tabEmpty = false) { | |||
| if ($('body').hasClass(CLASS_NAME_FULLSCREEN_MODE)) { | |||
| const windowHeight = $(window).height() | |||
| const navbarHeight = $(SELECTOR_TAB_NAV).outerHeight() | |||
| $(`${SELECTOR_TAB_EMPTY}, ${SELECTOR_TAB_LOADING}, ${SELECTOR_CONTENT_IFRAME}`).height(windowHeight - navbarHeight) | |||
| $(SELECTOR_CONTENT_WRAPPER).height(windowHeight) | |||
| } else { | |||
| const contentWrapperHeight = parseFloat($(SELECTOR_CONTENT_WRAPPER).css('height')) | |||
| const navbarHeight = $(SELECTOR_TAB_NAV).outerHeight() | |||
| if (tabEmpty == true) { | |||
| setTimeout(() => { | |||
| $(`${SELECTOR_TAB_EMPTY}, ${SELECTOR_TAB_LOADING}`).height(contentWrapperHeight - navbarHeight) | |||
| }, 50) | |||
| } else { | |||
| $(SELECTOR_CONTENT_IFRAME).height(contentWrapperHeight - navbarHeight) | |||
| } | |||
| } | |||
| } | |||
| // Static | |||
| static _jQueryInterface(operation, ...args) { | |||
| let data = $(this).data(DATA_KEY) | |||
| const _options = $.extend({}, Default, $(this).data()) | |||
| if (!data) { | |||
| data = new IFrame(this, _options) | |||
| $(this).data(DATA_KEY, data) | |||
| } | |||
| if (typeof operation === 'string' && /createTab|openTabSidebar|switchTab|removeActiveTab/.test(operation)) { | |||
| data[operation](...args) | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Data API | |||
| * ==================================================== | |||
| */ | |||
| $(window).on('load', () => { | |||
| IFrame._jQueryInterface.call($(SELECTOR_DATA_TOGGLE)) | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = IFrame._jQueryInterface | |||
| $.fn[NAME].Constructor = IFrame | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return IFrame._jQueryInterface | |||
| } | |||
| export default IFrame | |||
| @@ -0,0 +1,257 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE Layout.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'Layout' | |||
| const DATA_KEY = 'lte.layout' | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const SELECTOR_HEADER = '.main-header' | |||
| const SELECTOR_MAIN_SIDEBAR = '.main-sidebar' | |||
| const SELECTOR_SIDEBAR = '.main-sidebar .sidebar' | |||
| const SELECTOR_CONTENT = '.content-wrapper' | |||
| const SELECTOR_CONTROL_SIDEBAR_CONTENT = '.control-sidebar-content' | |||
| const SELECTOR_CONTROL_SIDEBAR_BTN = '[data-widget="control-sidebar"]' | |||
| const SELECTOR_FOOTER = '.main-footer' | |||
| const SELECTOR_PUSHMENU_BTN = '[data-widget="pushmenu"]' | |||
| const SELECTOR_LOGIN_BOX = '.login-box' | |||
| const SELECTOR_REGISTER_BOX = '.register-box' | |||
| const SELECTOR_PRELOADER = '.preloader' | |||
| const CLASS_NAME_SIDEBAR_COLLAPSED = 'sidebar-collapse' | |||
| const CLASS_NAME_SIDEBAR_FOCUSED = 'sidebar-focused' | |||
| const CLASS_NAME_LAYOUT_FIXED = 'layout-fixed' | |||
| const CLASS_NAME_CONTROL_SIDEBAR_SLIDE_OPEN = 'control-sidebar-slide-open' | |||
| const CLASS_NAME_CONTROL_SIDEBAR_OPEN = 'control-sidebar-open' | |||
| const Default = { | |||
| scrollbarTheme: 'os-theme-light', | |||
| scrollbarAutoHide: 'l', | |||
| panelAutoHeight: true, | |||
| panelAutoHeightMode: 'min-height', | |||
| preloadDuration: 200, | |||
| loginRegisterAutoHeight: true | |||
| } | |||
| /** | |||
| * Class Definition | |||
| * ==================================================== | |||
| */ | |||
| class Layout { | |||
| constructor(element, config) { | |||
| this._config = config | |||
| this._element = element | |||
| } | |||
| // Public | |||
| fixLayoutHeight(extra = null) { | |||
| const $body = $('body') | |||
| let controlSidebar = 0 | |||
| if ($body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_SLIDE_OPEN) || $body.hasClass(CLASS_NAME_CONTROL_SIDEBAR_OPEN) || extra === 'control_sidebar') { | |||
| controlSidebar = $(SELECTOR_CONTROL_SIDEBAR_CONTENT).outerHeight() | |||
| } | |||
| const heights = { | |||
| window: $(window).height(), | |||
| header: $(SELECTOR_HEADER).length > 0 ? $(SELECTOR_HEADER).outerHeight() : 0, | |||
| footer: $(SELECTOR_FOOTER).length > 0 ? $(SELECTOR_FOOTER).outerHeight() : 0, | |||
| sidebar: $(SELECTOR_SIDEBAR).length > 0 ? $(SELECTOR_SIDEBAR).height() : 0, | |||
| controlSidebar | |||
| } | |||
| const max = this._max(heights) | |||
| let offset = this._config.panelAutoHeight | |||
| if (offset === true) { | |||
| offset = 0 | |||
| } | |||
| const $contentSelector = $(SELECTOR_CONTENT) | |||
| if (offset !== false) { | |||
| if (max === heights.controlSidebar) { | |||
| $contentSelector.css(this._config.panelAutoHeightMode, (max + offset)) | |||
| } else if (max === heights.window) { | |||
| $contentSelector.css(this._config.panelAutoHeightMode, (max + offset) - heights.header - heights.footer) | |||
| } else { | |||
| $contentSelector.css(this._config.panelAutoHeightMode, (max + offset) - heights.header) | |||
| } | |||
| if (this._isFooterFixed()) { | |||
| $contentSelector.css(this._config.panelAutoHeightMode, parseFloat($contentSelector.css(this._config.panelAutoHeightMode)) + heights.footer) | |||
| } | |||
| } | |||
| if (!$body.hasClass(CLASS_NAME_LAYOUT_FIXED)) { | |||
| return | |||
| } | |||
| if (typeof $.fn.overlayScrollbars !== 'undefined') { | |||
| $(SELECTOR_SIDEBAR).overlayScrollbars({ | |||
| className: this._config.scrollbarTheme, | |||
| sizeAutoCapable: true, | |||
| scrollbars: { | |||
| autoHide: this._config.scrollbarAutoHide, | |||
| clickScrolling: true | |||
| } | |||
| }) | |||
| } else { | |||
| $(SELECTOR_SIDEBAR).css('overflow-y', 'auto') | |||
| } | |||
| } | |||
| fixLoginRegisterHeight() { | |||
| const $body = $('body') | |||
| const $selector = $(`${SELECTOR_LOGIN_BOX}, ${SELECTOR_REGISTER_BOX}`) | |||
| if ($selector.length === 0) { | |||
| $body.css('height', 'auto') | |||
| $('html').css('height', 'auto') | |||
| } else { | |||
| const boxHeight = $selector.height() | |||
| if ($body.css(this._config.panelAutoHeightMode) !== boxHeight) { | |||
| $body.css(this._config.panelAutoHeightMode, boxHeight) | |||
| } | |||
| } | |||
| } | |||
| // Private | |||
| _init() { | |||
| // Activate layout height watcher | |||
| this.fixLayoutHeight() | |||
| if (this._config.loginRegisterAutoHeight === true) { | |||
| this.fixLoginRegisterHeight() | |||
| } else if (this._config.loginRegisterAutoHeight === parseInt(this._config.loginRegisterAutoHeight, 10)) { | |||
| setInterval(this.fixLoginRegisterHeight, this._config.loginRegisterAutoHeight) | |||
| } | |||
| $(SELECTOR_SIDEBAR) | |||
| .on('collapsed.lte.treeview expanded.lte.treeview', () => { | |||
| this.fixLayoutHeight() | |||
| }) | |||
| $(SELECTOR_MAIN_SIDEBAR) | |||
| .on('mouseenter mouseleave', () => { | |||
| if ($('body').hasClass(CLASS_NAME_SIDEBAR_COLLAPSED)) { | |||
| this.fixLayoutHeight() | |||
| } | |||
| }) | |||
| $(SELECTOR_PUSHMENU_BTN) | |||
| .on('collapsed.lte.pushmenu shown.lte.pushmenu', () => { | |||
| setTimeout(() => { | |||
| this.fixLayoutHeight() | |||
| }, 300) | |||
| }) | |||
| $(SELECTOR_CONTROL_SIDEBAR_BTN) | |||
| .on('collapsed.lte.controlsidebar', () => { | |||
| this.fixLayoutHeight() | |||
| }) | |||
| .on('expanded.lte.controlsidebar', () => { | |||
| this.fixLayoutHeight('control_sidebar') | |||
| }) | |||
| $(window).resize(() => { | |||
| this.fixLayoutHeight() | |||
| }) | |||
| setTimeout(() => { | |||
| $('body.hold-transition').removeClass('hold-transition') | |||
| }, 50) | |||
| setTimeout(() => { | |||
| const $preloader = $(SELECTOR_PRELOADER) | |||
| if ($preloader) { | |||
| $preloader.css('height', 0) | |||
| setTimeout(() => { | |||
| $preloader.children().hide() | |||
| }, 200) | |||
| } | |||
| }, this._config.preloadDuration) | |||
| } | |||
| _max(numbers) { | |||
| // Calculate the maximum number in a list | |||
| let max = 0 | |||
| Object.keys(numbers).forEach(key => { | |||
| if (numbers[key] > max) { | |||
| max = numbers[key] | |||
| } | |||
| }) | |||
| return max | |||
| } | |||
| _isFooterFixed() { | |||
| return $(SELECTOR_FOOTER).css('position') === 'fixed' | |||
| } | |||
| // Static | |||
| static _jQueryInterface(config = '') { | |||
| return this.each(function () { | |||
| let data = $(this).data(DATA_KEY) | |||
| const _options = $.extend({}, Default, $(this).data()) | |||
| if (!data) { | |||
| data = new Layout($(this), _options) | |||
| $(this).data(DATA_KEY, data) | |||
| } | |||
| if (config === 'init' || config === '') { | |||
| data._init() | |||
| } else if (config === 'fixLayoutHeight' || config === 'fixLoginRegisterHeight') { | |||
| data[config]() | |||
| } | |||
| }) | |||
| } | |||
| } | |||
| /** | |||
| * Data API | |||
| * ==================================================== | |||
| */ | |||
| $(window).on('load', () => { | |||
| Layout._jQueryInterface.call($('body')) | |||
| }) | |||
| $(`${SELECTOR_SIDEBAR} a`) | |||
| .on('focusin', () => { | |||
| $(SELECTOR_MAIN_SIDEBAR).addClass(CLASS_NAME_SIDEBAR_FOCUSED) | |||
| }) | |||
| .on('focusout', () => { | |||
| $(SELECTOR_MAIN_SIDEBAR).removeClass(CLASS_NAME_SIDEBAR_FOCUSED) | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = Layout._jQueryInterface | |||
| $.fn[NAME].Constructor = Layout | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return Layout._jQueryInterface | |||
| } | |||
| export default Layout | |||
| @@ -0,0 +1,113 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE NavbarSearch.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'NavbarSearch' | |||
| const DATA_KEY = 'lte.navbar-search' | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const SELECTOR_TOGGLE_BUTTON = '[data-widget="navbar-search"]' | |||
| const SELECTOR_SEARCH_BLOCK = '.navbar-search-block' | |||
| const SELECTOR_SEARCH_INPUT = '.form-control' | |||
| const CLASS_NAME_OPEN = 'navbar-search-open' | |||
| const Default = { | |||
| resetOnClose: true, | |||
| target: SELECTOR_SEARCH_BLOCK | |||
| } | |||
| /** | |||
| * Class Definition | |||
| * ==================================================== | |||
| */ | |||
| class NavbarSearch { | |||
| constructor(_element, _options) { | |||
| this._element = _element | |||
| this._config = $.extend({}, Default, _options) | |||
| } | |||
| // Public | |||
| open() { | |||
| $(this._config.target).css('display', 'flex').hide().fadeIn().addClass(CLASS_NAME_OPEN) | |||
| $(`${this._config.target} ${SELECTOR_SEARCH_INPUT}`).focus() | |||
| } | |||
| close() { | |||
| $(this._config.target).fadeOut().removeClass(CLASS_NAME_OPEN) | |||
| if (this._config.resetOnClose) { | |||
| $(`${this._config.target} ${SELECTOR_SEARCH_INPUT}`).val('') | |||
| } | |||
| } | |||
| toggle() { | |||
| if ($(this._config.target).hasClass(CLASS_NAME_OPEN)) { | |||
| this.close() | |||
| } else { | |||
| this.open() | |||
| } | |||
| } | |||
| // Static | |||
| static _jQueryInterface(options) { | |||
| return this.each(function () { | |||
| let data = $(this).data(DATA_KEY) | |||
| const _options = $.extend({}, Default, $(this).data()) | |||
| if (!data) { | |||
| data = new NavbarSearch(this, _options) | |||
| $(this).data(DATA_KEY, data) | |||
| } | |||
| if (!/toggle|close|open/.test(options)) { | |||
| throw new Error(`Undefined method ${options}`) | |||
| } | |||
| data[options]() | |||
| }) | |||
| } | |||
| } | |||
| /** | |||
| * Data API | |||
| * ==================================================== | |||
| */ | |||
| $(document).on('click', SELECTOR_TOGGLE_BUTTON, event => { | |||
| event.preventDefault() | |||
| let button = $(event.currentTarget) | |||
| if (button.data('widget') !== 'navbar-search') { | |||
| button = button.closest(SELECTOR_TOGGLE_BUTTON) | |||
| } | |||
| NavbarSearch._jQueryInterface.call(button, 'toggle') | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = NavbarSearch._jQueryInterface | |||
| $.fn[NAME].Constructor = NavbarSearch | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return NavbarSearch._jQueryInterface | |||
| } | |||
| export default NavbarSearch | |||
| @@ -0,0 +1,223 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE PushMenu.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'PushMenu' | |||
| const DATA_KEY = 'lte.pushmenu' | |||
| const EVENT_KEY = `.${DATA_KEY}` | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const EVENT_COLLAPSED = `collapsed${EVENT_KEY}` | |||
| const EVENT_SHOWN = `shown${EVENT_KEY}` | |||
| const SELECTOR_TOGGLE_BUTTON = '[data-widget="pushmenu"]' | |||
| const SELECTOR_BODY = 'body' | |||
| const SELECTOR_OVERLAY = '#sidebar-overlay' | |||
| const SELECTOR_WRAPPER = '.wrapper' | |||
| const CLASS_NAME_COLLAPSED = 'sidebar-collapse' | |||
| const CLASS_NAME_OPEN = 'sidebar-open' | |||
| const CLASS_NAME_IS_OPENING = 'sidebar-is-opening' | |||
| const CLASS_NAME_CLOSED = 'sidebar-closed' | |||
| const Default = { | |||
| autoCollapseSize: 992, | |||
| enableRemember: false, | |||
| noTransitionAfterReload: true | |||
| } | |||
| /** | |||
| * Class Definition | |||
| * ==================================================== | |||
| */ | |||
| class PushMenu { | |||
| constructor(element, options) { | |||
| this._element = element | |||
| this._options = $.extend({}, Default, options) | |||
| if ($(SELECTOR_OVERLAY).length === 0) { | |||
| this._addOverlay() | |||
| } | |||
| this._init() | |||
| } | |||
| // Public | |||
| expand() { | |||
| const $bodySelector = $(SELECTOR_BODY) | |||
| if (this._options.autoCollapseSize && $(window).width() <= this._options.autoCollapseSize) { | |||
| $bodySelector.addClass(CLASS_NAME_OPEN) | |||
| } | |||
| $bodySelector.addClass(CLASS_NAME_IS_OPENING).removeClass(`${CLASS_NAME_COLLAPSED} ${CLASS_NAME_CLOSED}`).delay(50).queue(function () { | |||
| $bodySelector.removeClass(CLASS_NAME_IS_OPENING) | |||
| $(this).dequeue() | |||
| }) | |||
| if (this._options.enableRemember) { | |||
| localStorage.setItem(`remember${EVENT_KEY}`, CLASS_NAME_OPEN) | |||
| } | |||
| $(this._element).trigger($.Event(EVENT_SHOWN)) | |||
| } | |||
| collapse() { | |||
| const $bodySelector = $(SELECTOR_BODY) | |||
| if (this._options.autoCollapseSize && $(window).width() <= this._options.autoCollapseSize) { | |||
| $bodySelector.removeClass(CLASS_NAME_OPEN).addClass(CLASS_NAME_CLOSED) | |||
| } | |||
| $bodySelector.addClass(CLASS_NAME_COLLAPSED) | |||
| if (this._options.enableRemember) { | |||
| localStorage.setItem(`remember${EVENT_KEY}`, CLASS_NAME_COLLAPSED) | |||
| } | |||
| $(this._element).trigger($.Event(EVENT_COLLAPSED)) | |||
| } | |||
| toggle() { | |||
| if ($(SELECTOR_BODY).hasClass(CLASS_NAME_COLLAPSED)) { | |||
| this.expand() | |||
| } else { | |||
| this.collapse() | |||
| } | |||
| } | |||
| autoCollapse(resize = false) { | |||
| if (!this._options.autoCollapseSize) { | |||
| return | |||
| } | |||
| const $bodySelector = $(SELECTOR_BODY) | |||
| if ($(window).width() <= this._options.autoCollapseSize) { | |||
| if (!$bodySelector.hasClass(CLASS_NAME_OPEN)) { | |||
| this.collapse() | |||
| } | |||
| } else if (resize === true) { | |||
| if ($bodySelector.hasClass(CLASS_NAME_OPEN)) { | |||
| $bodySelector.removeClass(CLASS_NAME_OPEN) | |||
| } else if ($bodySelector.hasClass(CLASS_NAME_CLOSED)) { | |||
| this.expand() | |||
| } | |||
| } | |||
| } | |||
| remember() { | |||
| if (!this._options.enableRemember) { | |||
| return | |||
| } | |||
| const $body = $('body') | |||
| const toggleState = localStorage.getItem(`remember${EVENT_KEY}`) | |||
| if (toggleState === CLASS_NAME_COLLAPSED) { | |||
| if (this._options.noTransitionAfterReload) { | |||
| $body.addClass('hold-transition').addClass(CLASS_NAME_COLLAPSED).delay(50).queue(function () { | |||
| $(this).removeClass('hold-transition') | |||
| $(this).dequeue() | |||
| }) | |||
| } else { | |||
| $body.addClass(CLASS_NAME_COLLAPSED) | |||
| } | |||
| } else if (this._options.noTransitionAfterReload) { | |||
| $body.addClass('hold-transition').removeClass(CLASS_NAME_COLLAPSED).delay(50).queue(function () { | |||
| $(this).removeClass('hold-transition') | |||
| $(this).dequeue() | |||
| }) | |||
| } else { | |||
| $body.removeClass(CLASS_NAME_COLLAPSED) | |||
| } | |||
| } | |||
| // Private | |||
| _init() { | |||
| this.remember() | |||
| this.autoCollapse() | |||
| $(window).resize(() => { | |||
| this.autoCollapse(true) | |||
| }) | |||
| } | |||
| _addOverlay() { | |||
| const overlay = $('<div />', { | |||
| id: 'sidebar-overlay' | |||
| }) | |||
| overlay.on('click', () => { | |||
| this.collapse() | |||
| }) | |||
| $(SELECTOR_WRAPPER).append(overlay) | |||
| } | |||
| // Static | |||
| static _jQueryInterface(operation) { | |||
| return this.each(function () { | |||
| let data = $(this).data(DATA_KEY) | |||
| const _options = $.extend({}, Default, $(this).data()) | |||
| if (!data) { | |||
| data = new PushMenu(this, _options) | |||
| $(this).data(DATA_KEY, data) | |||
| } | |||
| if (typeof operation === 'string' && /collapse|expand|toggle/.test(operation)) { | |||
| data[operation]() | |||
| } | |||
| }) | |||
| } | |||
| } | |||
| /** | |||
| * Data API | |||
| * ==================================================== | |||
| */ | |||
| $(document).on('click', SELECTOR_TOGGLE_BUTTON, event => { | |||
| event.preventDefault() | |||
| let button = event.currentTarget | |||
| if ($(button).data('widget') !== 'pushmenu') { | |||
| button = $(button).closest(SELECTOR_TOGGLE_BUTTON) | |||
| } | |||
| PushMenu._jQueryInterface.call($(button), 'toggle') | |||
| }) | |||
| $(window).on('load', () => { | |||
| PushMenu._jQueryInterface.call($(SELECTOR_TOGGLE_BUTTON)) | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = PushMenu._jQueryInterface | |||
| $.fn[NAME].Constructor = PushMenu | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return PushMenu._jQueryInterface | |||
| } | |||
| export default PushMenu | |||
| @@ -0,0 +1,298 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE SidebarSearch.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $, { trim } from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'SidebarSearch' | |||
| const DATA_KEY = 'lte.sidebar-search' | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const CLASS_NAME_OPEN = 'sidebar-search-open' | |||
| const CLASS_NAME_ICON_SEARCH = 'fa-search' | |||
| const CLASS_NAME_ICON_CLOSE = 'fa-times' | |||
| const CLASS_NAME_HEADER = 'nav-header' | |||
| const CLASS_NAME_SEARCH_RESULTS = 'sidebar-search-results' | |||
| const CLASS_NAME_LIST_GROUP = 'list-group' | |||
| const SELECTOR_DATA_WIDGET = '[data-widget="sidebar-search"]' | |||
| const SELECTOR_SIDEBAR = '.main-sidebar .nav-sidebar' | |||
| const SELECTOR_NAV_LINK = '.nav-link' | |||
| const SELECTOR_NAV_TREEVIEW = '.nav-treeview' | |||
| const SELECTOR_SEARCH_INPUT = `${SELECTOR_DATA_WIDGET} .form-control` | |||
| const SELECTOR_SEARCH_BUTTON = `${SELECTOR_DATA_WIDGET} .btn` | |||
| const SELECTOR_SEARCH_ICON = `${SELECTOR_SEARCH_BUTTON} i` | |||
| const SELECTOR_SEARCH_LIST_GROUP = `.${CLASS_NAME_LIST_GROUP}` | |||
| const SELECTOR_SEARCH_RESULTS = `.${CLASS_NAME_SEARCH_RESULTS}` | |||
| const SELECTOR_SEARCH_RESULTS_GROUP = `${SELECTOR_SEARCH_RESULTS} .${CLASS_NAME_LIST_GROUP}` | |||
| const Default = { | |||
| arrowSign: '->', | |||
| minLength: 3, | |||
| maxResults: 7, | |||
| highlightName: true, | |||
| highlightPath: false, | |||
| highlightClass: 'text-light', | |||
| notFoundText: 'No element found!' | |||
| } | |||
| const SearchItems = [] | |||
| /** | |||
| * Class Definition | |||
| * ==================================================== | |||
| */ | |||
| class SidebarSearch { | |||
| constructor(_element, _options) { | |||
| this.element = _element | |||
| this.options = $.extend({}, Default, _options) | |||
| this.items = [] | |||
| } | |||
| // Public | |||
| init() { | |||
| if ($(SELECTOR_DATA_WIDGET).length === 0) { | |||
| return | |||
| } | |||
| if ($(SELECTOR_DATA_WIDGET).next(SELECTOR_SEARCH_RESULTS).length === 0) { | |||
| $(SELECTOR_DATA_WIDGET).after( | |||
| $('<div />', { class: CLASS_NAME_SEARCH_RESULTS }) | |||
| ) | |||
| } | |||
| if ($(SELECTOR_SEARCH_RESULTS).children(SELECTOR_SEARCH_LIST_GROUP).length === 0) { | |||
| $(SELECTOR_SEARCH_RESULTS).append( | |||
| $('<div />', { class: CLASS_NAME_LIST_GROUP }) | |||
| ) | |||
| } | |||
| this._addNotFound() | |||
| $(SELECTOR_SIDEBAR).children().each((i, child) => { | |||
| this._parseItem(child) | |||
| }) | |||
| } | |||
| search() { | |||
| const searchValue = $(SELECTOR_SEARCH_INPUT).val().toLowerCase() | |||
| if (searchValue.length < this.options.minLength) { | |||
| $(SELECTOR_SEARCH_RESULTS_GROUP).empty() | |||
| this._addNotFound() | |||
| this.close() | |||
| return | |||
| } | |||
| const searchResults = SearchItems.filter(item => (item.name).toLowerCase().includes(searchValue)) | |||
| const endResults = $(searchResults.slice(0, this.options.maxResults)) | |||
| $(SELECTOR_SEARCH_RESULTS_GROUP).empty() | |||
| if (endResults.length === 0) { | |||
| this._addNotFound() | |||
| } else { | |||
| endResults.each((i, result) => { | |||
| $(SELECTOR_SEARCH_RESULTS_GROUP).append(this._renderItem(escape(result.name), escape(result.link), result.path)) | |||
| }) | |||
| } | |||
| this.open() | |||
| } | |||
| open() { | |||
| $(SELECTOR_DATA_WIDGET).parent().addClass(CLASS_NAME_OPEN) | |||
| $(SELECTOR_SEARCH_ICON).removeClass(CLASS_NAME_ICON_SEARCH).addClass(CLASS_NAME_ICON_CLOSE) | |||
| } | |||
| close() { | |||
| $(SELECTOR_DATA_WIDGET).parent().removeClass(CLASS_NAME_OPEN) | |||
| $(SELECTOR_SEARCH_ICON).removeClass(CLASS_NAME_ICON_CLOSE).addClass(CLASS_NAME_ICON_SEARCH) | |||
| } | |||
| toggle() { | |||
| if ($(SELECTOR_DATA_WIDGET).parent().hasClass(CLASS_NAME_OPEN)) { | |||
| this.close() | |||
| } else { | |||
| this.open() | |||
| } | |||
| } | |||
| // Private | |||
| _parseItem(item, path = []) { | |||
| if ($(item).hasClass(CLASS_NAME_HEADER)) { | |||
| return | |||
| } | |||
| const itemObject = {} | |||
| const navLink = $(item).clone().find(`> ${SELECTOR_NAV_LINK}`) | |||
| const navTreeview = $(item).clone().find(`> ${SELECTOR_NAV_TREEVIEW}`) | |||
| const link = navLink.attr('href') | |||
| const name = navLink.find('p').children().remove().end().text() | |||
| itemObject.name = this._trimText(name) | |||
| itemObject.link = link | |||
| itemObject.path = path | |||
| if (navTreeview.length === 0) { | |||
| SearchItems.push(itemObject) | |||
| } else { | |||
| const newPath = itemObject.path.concat([itemObject.name]) | |||
| navTreeview.children().each((i, child) => { | |||
| this._parseItem(child, newPath) | |||
| }) | |||
| } | |||
| } | |||
| _trimText(text) { | |||
| return trim(text.replace(/(\r\n|\n|\r)/gm, ' ')) | |||
| } | |||
| _renderItem(name, link, path) { | |||
| path = path.join(` ${this.options.arrowSign} `) | |||
| name = unescape(name) | |||
| if (this.options.highlightName || this.options.highlightPath) { | |||
| const searchValue = $(SELECTOR_SEARCH_INPUT).val().toLowerCase() | |||
| const regExp = new RegExp(searchValue, 'gi') | |||
| if (this.options.highlightName) { | |||
| name = name.replace( | |||
| regExp, | |||
| str => { | |||
| return `<strong class="${this.options.highlightClass}">${str}</strong>` | |||
| } | |||
| ) | |||
| } | |||
| if (this.options.highlightPath) { | |||
| path = path.replace( | |||
| regExp, | |||
| str => { | |||
| return `<strong class="${this.options.highlightClass}">${str}</strong>` | |||
| } | |||
| ) | |||
| } | |||
| } | |||
| const groupItemElement = $('<a/>', { | |||
| href: link, | |||
| class: 'list-group-item' | |||
| }) | |||
| const searchTitleElement = $('<div/>', { | |||
| class: 'search-title' | |||
| }).html(name) | |||
| const searchPathElement = $('<div/>', { | |||
| class: 'search-path' | |||
| }).html(path) | |||
| groupItemElement.append(searchTitleElement).append(searchPathElement) | |||
| return groupItemElement | |||
| } | |||
| _addNotFound() { | |||
| $(SELECTOR_SEARCH_RESULTS_GROUP).append(this._renderItem(this.options.notFoundText, '#', [])) | |||
| } | |||
| // Static | |||
| static _jQueryInterface(config) { | |||
| let data = $(this).data(DATA_KEY) | |||
| if (!data) { | |||
| data = $(this).data() | |||
| } | |||
| const _options = $.extend({}, Default, typeof config === 'object' ? config : data) | |||
| const plugin = new SidebarSearch($(this), _options) | |||
| $(this).data(DATA_KEY, typeof config === 'object' ? config : data) | |||
| if (typeof config === 'string' && /init|toggle|close|open|search/.test(config)) { | |||
| plugin[config]() | |||
| } else { | |||
| plugin.init() | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Data API | |||
| * ==================================================== | |||
| */ | |||
| $(document).on('click', SELECTOR_SEARCH_BUTTON, event => { | |||
| event.preventDefault() | |||
| SidebarSearch._jQueryInterface.call($(SELECTOR_DATA_WIDGET), 'toggle') | |||
| }) | |||
| $(document).on('keyup', SELECTOR_SEARCH_INPUT, event => { | |||
| if (event.keyCode == 38) { | |||
| event.preventDefault() | |||
| $(SELECTOR_SEARCH_RESULTS_GROUP).children().last().focus() | |||
| return | |||
| } | |||
| if (event.keyCode == 40) { | |||
| event.preventDefault() | |||
| $(SELECTOR_SEARCH_RESULTS_GROUP).children().first().focus() | |||
| return | |||
| } | |||
| setTimeout(() => { | |||
| SidebarSearch._jQueryInterface.call($(SELECTOR_DATA_WIDGET), 'search') | |||
| }, 100) | |||
| }) | |||
| $(document).on('keydown', SELECTOR_SEARCH_RESULTS_GROUP, event => { | |||
| const $focused = $(':focus') | |||
| if (event.keyCode == 38) { | |||
| event.preventDefault() | |||
| if ($focused.is(':first-child')) { | |||
| $focused.siblings().last().focus() | |||
| } else { | |||
| $focused.prev().focus() | |||
| } | |||
| } | |||
| if (event.keyCode == 40) { | |||
| event.preventDefault() | |||
| if ($focused.is(':last-child')) { | |||
| $focused.siblings().first().focus() | |||
| } else { | |||
| $focused.next().focus() | |||
| } | |||
| } | |||
| }) | |||
| $(window).on('load', () => { | |||
| SidebarSearch._jQueryInterface.call($(SELECTOR_DATA_WIDGET), 'init') | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = SidebarSearch._jQueryInterface | |||
| $.fn[NAME].Constructor = SidebarSearch | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return SidebarSearch._jQueryInterface | |||
| } | |||
| export default SidebarSearch | |||
| @@ -0,0 +1,209 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE Toasts.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'Toasts' | |||
| const DATA_KEY = 'lte.toasts' | |||
| const EVENT_KEY = `.${DATA_KEY}` | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const EVENT_INIT = `init${EVENT_KEY}` | |||
| const EVENT_CREATED = `created${EVENT_KEY}` | |||
| const EVENT_REMOVED = `removed${EVENT_KEY}` | |||
| const SELECTOR_CONTAINER_TOP_RIGHT = '#toastsContainerTopRight' | |||
| const SELECTOR_CONTAINER_TOP_LEFT = '#toastsContainerTopLeft' | |||
| const SELECTOR_CONTAINER_BOTTOM_RIGHT = '#toastsContainerBottomRight' | |||
| const SELECTOR_CONTAINER_BOTTOM_LEFT = '#toastsContainerBottomLeft' | |||
| const CLASS_NAME_TOP_RIGHT = 'toasts-top-right' | |||
| const CLASS_NAME_TOP_LEFT = 'toasts-top-left' | |||
| const CLASS_NAME_BOTTOM_RIGHT = 'toasts-bottom-right' | |||
| const CLASS_NAME_BOTTOM_LEFT = 'toasts-bottom-left' | |||
| const POSITION_TOP_RIGHT = 'topRight' | |||
| const POSITION_TOP_LEFT = 'topLeft' | |||
| const POSITION_BOTTOM_RIGHT = 'bottomRight' | |||
| const POSITION_BOTTOM_LEFT = 'bottomLeft' | |||
| const Default = { | |||
| position: POSITION_TOP_RIGHT, | |||
| fixed: true, | |||
| autohide: false, | |||
| autoremove: true, | |||
| delay: 1000, | |||
| fade: true, | |||
| icon: null, | |||
| image: null, | |||
| imageAlt: null, | |||
| imageHeight: '25px', | |||
| title: null, | |||
| subtitle: null, | |||
| close: true, | |||
| body: null, | |||
| class: null | |||
| } | |||
| /** | |||
| * Class Definition | |||
| * ==================================================== | |||
| */ | |||
| class Toasts { | |||
| constructor(element, config) { | |||
| this._config = config | |||
| this._prepareContainer() | |||
| $('body').trigger($.Event(EVENT_INIT)) | |||
| } | |||
| // Public | |||
| create() { | |||
| const toast = $('<div class="toast" role="alert" aria-live="assertive" aria-atomic="true"/>') | |||
| toast.data('autohide', this._config.autohide) | |||
| toast.data('animation', this._config.fade) | |||
| if (this._config.class) { | |||
| toast.addClass(this._config.class) | |||
| } | |||
| if (this._config.delay && this._config.delay != 500) { | |||
| toast.data('delay', this._config.delay) | |||
| } | |||
| const toastHeader = $('<div class="toast-header">') | |||
| if (this._config.image != null) { | |||
| const toastImage = $('<img />').addClass('rounded mr-2').attr('src', this._config.image).attr('alt', this._config.imageAlt) | |||
| if (this._config.imageHeight != null) { | |||
| toastImage.height(this._config.imageHeight).width('auto') | |||
| } | |||
| toastHeader.append(toastImage) | |||
| } | |||
| if (this._config.icon != null) { | |||
| toastHeader.append($('<i />').addClass('mr-2').addClass(this._config.icon)) | |||
| } | |||
| if (this._config.title != null) { | |||
| toastHeader.append($('<strong />').addClass('mr-auto').html(this._config.title)) | |||
| } | |||
| if (this._config.subtitle != null) { | |||
| toastHeader.append($('<small />').html(this._config.subtitle)) | |||
| } | |||
| if (this._config.close == true) { | |||
| const toastClose = $('<button data-dismiss="toast" />').attr('type', 'button').addClass('ml-2 mb-1 close').attr('aria-label', 'Close').append('<span aria-hidden="true">×</span>') | |||
| if (this._config.title == null) { | |||
| toastClose.toggleClass('ml-2 ml-auto') | |||
| } | |||
| toastHeader.append(toastClose) | |||
| } | |||
| toast.append(toastHeader) | |||
| if (this._config.body != null) { | |||
| toast.append($('<div class="toast-body" />').html(this._config.body)) | |||
| } | |||
| $(this._getContainerId()).prepend(toast) | |||
| const $body = $('body') | |||
| $body.trigger($.Event(EVENT_CREATED)) | |||
| toast.toast('show') | |||
| if (this._config.autoremove) { | |||
| toast.on('hidden.bs.toast', function () { | |||
| $(this).delay(200).remove() | |||
| $body.trigger($.Event(EVENT_REMOVED)) | |||
| }) | |||
| } | |||
| } | |||
| // Static | |||
| _getContainerId() { | |||
| if (this._config.position == POSITION_TOP_RIGHT) { | |||
| return SELECTOR_CONTAINER_TOP_RIGHT | |||
| } | |||
| if (this._config.position == POSITION_TOP_LEFT) { | |||
| return SELECTOR_CONTAINER_TOP_LEFT | |||
| } | |||
| if (this._config.position == POSITION_BOTTOM_RIGHT) { | |||
| return SELECTOR_CONTAINER_BOTTOM_RIGHT | |||
| } | |||
| if (this._config.position == POSITION_BOTTOM_LEFT) { | |||
| return SELECTOR_CONTAINER_BOTTOM_LEFT | |||
| } | |||
| } | |||
| _prepareContainer() { | |||
| if ($(this._getContainerId()).length === 0) { | |||
| const container = $('<div />').attr('id', this._getContainerId().replace('#', '')) | |||
| if (this._config.position == POSITION_TOP_RIGHT) { | |||
| container.addClass(CLASS_NAME_TOP_RIGHT) | |||
| } else if (this._config.position == POSITION_TOP_LEFT) { | |||
| container.addClass(CLASS_NAME_TOP_LEFT) | |||
| } else if (this._config.position == POSITION_BOTTOM_RIGHT) { | |||
| container.addClass(CLASS_NAME_BOTTOM_RIGHT) | |||
| } else if (this._config.position == POSITION_BOTTOM_LEFT) { | |||
| container.addClass(CLASS_NAME_BOTTOM_LEFT) | |||
| } | |||
| $('body').append(container) | |||
| } | |||
| if (this._config.fixed) { | |||
| $(this._getContainerId()).addClass('fixed') | |||
| } else { | |||
| $(this._getContainerId()).removeClass('fixed') | |||
| } | |||
| } | |||
| // Static | |||
| static _jQueryInterface(option, config) { | |||
| return this.each(function () { | |||
| const _options = $.extend({}, Default, config) | |||
| const toast = new Toasts($(this), _options) | |||
| if (option === 'create') { | |||
| toast[option]() | |||
| } | |||
| }) | |||
| } | |||
| } | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = Toasts._jQueryInterface | |||
| $.fn[NAME].Constructor = Toasts | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return Toasts._jQueryInterface | |||
| } | |||
| export default Toasts | |||
| @@ -0,0 +1,118 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE TodoList.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'TodoList' | |||
| const DATA_KEY = 'lte.todolist' | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const SELECTOR_DATA_TOGGLE = '[data-widget="todo-list"]' | |||
| const CLASS_NAME_TODO_LIST_DONE = 'done' | |||
| const Default = { | |||
| onCheck(item) { | |||
| return item | |||
| }, | |||
| onUnCheck(item) { | |||
| return item | |||
| } | |||
| } | |||
| /** | |||
| * Class Definition | |||
| * ==================================================== | |||
| */ | |||
| class TodoList { | |||
| constructor(element, config) { | |||
| this._config = config | |||
| this._element = element | |||
| this._init() | |||
| } | |||
| // Public | |||
| toggle(item) { | |||
| item.parents('li').toggleClass(CLASS_NAME_TODO_LIST_DONE) | |||
| if (!$(item).prop('checked')) { | |||
| this.unCheck($(item)) | |||
| return | |||
| } | |||
| this.check(item) | |||
| } | |||
| check(item) { | |||
| this._config.onCheck.call(item) | |||
| } | |||
| unCheck(item) { | |||
| this._config.onUnCheck.call(item) | |||
| } | |||
| // Private | |||
| _init() { | |||
| const $toggleSelector = this._element | |||
| $toggleSelector.find('input:checkbox:checked').parents('li').toggleClass(CLASS_NAME_TODO_LIST_DONE) | |||
| $toggleSelector.on('change', 'input:checkbox', event => { | |||
| this.toggle($(event.target)) | |||
| }) | |||
| } | |||
| // Static | |||
| static _jQueryInterface(config) { | |||
| return this.each(function () { | |||
| let data = $(this).data(DATA_KEY) | |||
| if (!data) { | |||
| data = $(this).data() | |||
| } | |||
| const _options = $.extend({}, Default, typeof config === 'object' ? config : data) | |||
| const plugin = new TodoList($(this), _options) | |||
| $(this).data(DATA_KEY, typeof config === 'object' ? config : data) | |||
| if (config === 'init') { | |||
| plugin[config]() | |||
| } | |||
| }) | |||
| } | |||
| } | |||
| /** | |||
| * Data API | |||
| * ==================================================== | |||
| */ | |||
| $(window).on('load', () => { | |||
| TodoList._jQueryInterface.call($(SELECTOR_DATA_TOGGLE)) | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = TodoList._jQueryInterface | |||
| $.fn[NAME].Constructor = TodoList | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return TodoList._jQueryInterface | |||
| } | |||
| export default TodoList | |||
| @@ -0,0 +1,175 @@ | |||
| /** | |||
| * -------------------------------------------- | |||
| * AdminLTE Treeview.js | |||
| * License MIT | |||
| * -------------------------------------------- | |||
| */ | |||
| import $ from 'jquery' | |||
| /** | |||
| * Constants | |||
| * ==================================================== | |||
| */ | |||
| const NAME = 'Treeview' | |||
| const DATA_KEY = 'lte.treeview' | |||
| const EVENT_KEY = `.${DATA_KEY}` | |||
| const JQUERY_NO_CONFLICT = $.fn[NAME] | |||
| const EVENT_EXPANDED = `expanded${EVENT_KEY}` | |||
| const EVENT_COLLAPSED = `collapsed${EVENT_KEY}` | |||
| const EVENT_LOAD_DATA_API = `load${EVENT_KEY}` | |||
| const SELECTOR_LI = '.nav-item' | |||
| const SELECTOR_LINK = '.nav-link' | |||
| const SELECTOR_TREEVIEW_MENU = '.nav-treeview' | |||
| const SELECTOR_OPEN = '.menu-open' | |||
| const SELECTOR_DATA_WIDGET = '[data-widget="treeview"]' | |||
| const CLASS_NAME_OPEN = 'menu-open' | |||
| const CLASS_NAME_IS_OPENING = 'menu-is-opening' | |||
| const CLASS_NAME_SIDEBAR_COLLAPSED = 'sidebar-collapse' | |||
| const Default = { | |||
| trigger: `${SELECTOR_DATA_WIDGET} ${SELECTOR_LINK}`, | |||
| animationSpeed: 300, | |||
| accordion: true, | |||
| expandSidebar: false, | |||
| sidebarButtonSelector: '[data-widget="pushmenu"]' | |||
| } | |||
| /** | |||
| * Class Definition | |||
| * ==================================================== | |||
| */ | |||
| class Treeview { | |||
| constructor(element, config) { | |||
| this._config = config | |||
| this._element = element | |||
| } | |||
| // Public | |||
| init() { | |||
| $(`${SELECTOR_LI}${SELECTOR_OPEN} ${SELECTOR_TREEVIEW_MENU}${SELECTOR_OPEN}`).css('display', 'block') | |||
| this._setupListeners() | |||
| } | |||
| expand(treeviewMenu, parentLi) { | |||
| const expandedEvent = $.Event(EVENT_EXPANDED) | |||
| if (this._config.accordion) { | |||
| const openMenuLi = parentLi.siblings(SELECTOR_OPEN).first() | |||
| const openTreeview = openMenuLi.find(SELECTOR_TREEVIEW_MENU).first() | |||
| this.collapse(openTreeview, openMenuLi) | |||
| } | |||
| parentLi.addClass(CLASS_NAME_IS_OPENING) | |||
| treeviewMenu.stop().slideDown(this._config.animationSpeed, () => { | |||
| parentLi.addClass(CLASS_NAME_OPEN) | |||
| $(this._element).trigger(expandedEvent) | |||
| }) | |||
| if (this._config.expandSidebar) { | |||
| this._expandSidebar() | |||
| } | |||
| } | |||
| collapse(treeviewMenu, parentLi) { | |||
| const collapsedEvent = $.Event(EVENT_COLLAPSED) | |||
| parentLi.removeClass(`${CLASS_NAME_IS_OPENING} ${CLASS_NAME_OPEN}`) | |||
| treeviewMenu.stop().slideUp(this._config.animationSpeed, () => { | |||
| $(this._element).trigger(collapsedEvent) | |||
| treeviewMenu.find(`${SELECTOR_OPEN} > ${SELECTOR_TREEVIEW_MENU}`).slideUp() | |||
| treeviewMenu.find(SELECTOR_OPEN).removeClass(CLASS_NAME_OPEN) | |||
| }) | |||
| } | |||
| toggle(event) { | |||
| const $relativeTarget = $(event.currentTarget) | |||
| const $parent = $relativeTarget.parent() | |||
| let treeviewMenu = $parent.find(`> ${SELECTOR_TREEVIEW_MENU}`) | |||
| if (!treeviewMenu.is(SELECTOR_TREEVIEW_MENU)) { | |||
| if (!$parent.is(SELECTOR_LI)) { | |||
| treeviewMenu = $parent.parent().find(`> ${SELECTOR_TREEVIEW_MENU}`) | |||
| } | |||
| if (!treeviewMenu.is(SELECTOR_TREEVIEW_MENU)) { | |||
| return | |||
| } | |||
| } | |||
| event.preventDefault() | |||
| const parentLi = $relativeTarget.parents(SELECTOR_LI).first() | |||
| const isOpen = parentLi.hasClass(CLASS_NAME_OPEN) | |||
| if (isOpen) { | |||
| this.collapse($(treeviewMenu), parentLi) | |||
| } else { | |||
| this.expand($(treeviewMenu), parentLi) | |||
| } | |||
| } | |||
| // Private | |||
| _setupListeners() { | |||
| const elementId = this._element.attr('id') !== undefined ? `#${this._element.attr('id')}` : '' | |||
| $(document).on('click', `${elementId}${this._config.trigger}`, event => { | |||
| this.toggle(event) | |||
| }) | |||
| } | |||
| _expandSidebar() { | |||
| if ($('body').hasClass(CLASS_NAME_SIDEBAR_COLLAPSED)) { | |||
| $(this._config.sidebarButtonSelector).PushMenu('expand') | |||
| } | |||
| } | |||
| // Static | |||
| static _jQueryInterface(config) { | |||
| return this.each(function () { | |||
| let data = $(this).data(DATA_KEY) | |||
| const _options = $.extend({}, Default, $(this).data()) | |||
| if (!data) { | |||
| data = new Treeview($(this), _options) | |||
| $(this).data(DATA_KEY, data) | |||
| } | |||
| if (config === 'init') { | |||
| data[config]() | |||
| } | |||
| }) | |||
| } | |||
| } | |||
| /** | |||
| * Data API | |||
| * ==================================================== | |||
| */ | |||
| $(window).on(EVENT_LOAD_DATA_API, () => { | |||
| $(SELECTOR_DATA_WIDGET).each(function () { | |||
| Treeview._jQueryInterface.call($(this), 'init') | |||
| }) | |||
| }) | |||
| /** | |||
| * jQuery API | |||
| * ==================================================== | |||
| */ | |||
| $.fn[NAME] = Treeview._jQueryInterface | |||
| $.fn[NAME].Constructor = Treeview | |||
| $.fn[NAME].noConflict = function () { | |||
| $.fn[NAME] = JQUERY_NO_CONFLICT | |||
| return Treeview._jQueryInterface | |||
| } | |||
| export default Treeview | |||
| @@ -0,0 +1,14 @@ | |||
| { | |||
| "env": { | |||
| "browser": false, | |||
| "node": true | |||
| }, | |||
| "parserOptions": { | |||
| "sourceType": "script" | |||
| }, | |||
| "extends": "../../.eslintrc.json", | |||
| "rules": { | |||
| "no-console": "off", | |||
| "strict": "error" | |||
| } | |||
| } | |||
| @@ -0,0 +1,48 @@ | |||
| 'use strict' | |||
| const Plugins = [ | |||
| // AdminLTE Dist | |||
| { | |||
| from: 'dist/css/', | |||
| to: 'docs/assets/css/' | |||
| }, | |||
| { | |||
| from: 'dist/js/', | |||
| to: 'docs/assets/js/' | |||
| }, | |||
| // jQuery | |||
| { | |||
| from: 'node_modules/jquery/dist/', | |||
| to: 'docs/assets/plugins/jquery/' | |||
| }, | |||
| // Popper | |||
| { | |||
| from: 'node_modules/popper.js/dist/', | |||
| to: 'docs/assets/plugins/popper/' | |||
| }, | |||
| // Bootstrap | |||
| { | |||
| from: 'node_modules/bootstrap/dist/js/', | |||
| to: 'docs/assets/plugins/bootstrap/js/' | |||
| }, | |||
| // Font Awesome | |||
| { | |||
| from: 'node_modules/@fortawesome/fontawesome-free/css/', | |||
| to: 'docs/assets/plugins/fontawesome-free/css/' | |||
| }, | |||
| { | |||
| from: 'node_modules/@fortawesome/fontawesome-free/webfonts/', | |||
| to: 'docs/assets/plugins/fontawesome-free/webfonts/' | |||
| }, | |||
| // overlayScrollbars | |||
| { | |||
| from: 'node_modules/overlayscrollbars/js/', | |||
| to: 'docs/assets/plugins/overlayScrollbars/js/' | |||
| }, | |||
| { | |||
| from: 'node_modules/overlayscrollbars/css/', | |||
| to: 'docs/assets/plugins/overlayScrollbars/css/' | |||
| } | |||
| ] | |||
| module.exports = Plugins | |||
| @@ -0,0 +1,58 @@ | |||
| #!/usr/bin/env node | |||
| 'use strict' | |||
| const path = require('path') | |||
| const fse = require('fs-extra') | |||
| const fs = require('fs') | |||
| const Plugins = require('./DocsPlugins') | |||
| class Publish { | |||
| constructor() { | |||
| this.options = { | |||
| verbose: false | |||
| } | |||
| this.getArguments() | |||
| } | |||
| getArguments() { | |||
| if (process.argv.length > 2) { | |||
| const arg = process.argv[2] | |||
| switch (arg) { | |||
| case '-v': | |||
| case '--verbose': | |||
| this.options.verbose = true | |||
| break | |||
| default: | |||
| throw new Error(`Unknown option ${arg}`) | |||
| } | |||
| } | |||
| } | |||
| run() { | |||
| // Publish files | |||
| Plugins.forEach(module => { | |||
| try { | |||
| fse.copySync(module.from, module.to, { | |||
| // Skip copying dot files | |||
| filter(src) { | |||
| return !path.basename(src).startsWith('.') | |||
| } | |||
| }) | |||
| if (this.options.verbose) { | |||
| console.log(`Copied ${module.from} to ${module.to}`) | |||
| } | |||
| } catch (error) { | |||
| console.error(`Error: ${error}`) | |||
| } | |||
| }) | |||
| const insertText = '---\r\nlayout: page\r\ntitle: \r\n---\r\n' | |||
| fs.writeFileSync('docs/how-to-contribute.md', insertText + fs.readFileSync('.github/CONTRIBUTING.md', 'utf8')) | |||
| } | |||
| } | |||
| (new Publish()).run() | |||
| @@ -0,0 +1,449 @@ | |||
| 'use strict' | |||
| const Plugins = [ | |||
| // jQuery | |||
| { | |||
| from: 'node_modules/jquery/dist', | |||
| to: 'plugins/jquery' | |||
| }, | |||
| // Popper | |||
| { | |||
| from: 'node_modules/popper.js/dist', | |||
| to: 'plugins/popper' | |||
| }, | |||
| // Bootstrap | |||
| { | |||
| from: 'node_modules/bootstrap/dist/js', | |||
| to: 'plugins/bootstrap/js' | |||
| }, | |||
| // Font Awesome | |||
| { | |||
| from: 'node_modules/@fortawesome/fontawesome-free/css', | |||
| to: 'plugins/fontawesome-free/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/@fortawesome/fontawesome-free/webfonts', | |||
| to: 'plugins/fontawesome-free/webfonts' | |||
| }, | |||
| // overlayScrollbars | |||
| { | |||
| from: 'node_modules/overlayscrollbars/js', | |||
| to: 'plugins/overlayScrollbars/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/overlayscrollbars/css', | |||
| to: 'plugins/overlayScrollbars/css' | |||
| }, | |||
| // Chart.js | |||
| { | |||
| from: 'node_modules/chart.js/dist/', | |||
| to: 'plugins/chart.js' | |||
| }, | |||
| // jQuery UI | |||
| { | |||
| from: 'node_modules/jquery-ui-dist/', | |||
| to: 'plugins/jquery-ui' | |||
| }, | |||
| // Flot | |||
| { | |||
| from: 'node_modules/flot/dist/es5/', | |||
| to: 'plugins/flot' | |||
| }, | |||
| { | |||
| from: 'node_modules/flot/source/', | |||
| to: 'plugins/flot/plugins' | |||
| }, | |||
| // Summernote | |||
| { | |||
| from: 'node_modules/summernote/dist/', | |||
| to: 'plugins/summernote' | |||
| }, | |||
| // Bootstrap Slider | |||
| { | |||
| from: 'node_modules/bootstrap-slider/dist/', | |||
| to: 'plugins/bootstrap-slider' | |||
| }, | |||
| { | |||
| from: 'node_modules/bootstrap-slider/dist/css', | |||
| to: 'plugins/bootstrap-slider/css' | |||
| }, | |||
| // Bootstrap Colorpicker | |||
| { | |||
| from: 'node_modules/bootstrap-colorpicker/dist/js', | |||
| to: 'plugins/bootstrap-colorpicker/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/bootstrap-colorpicker/dist/css', | |||
| to: 'plugins/bootstrap-colorpicker/css' | |||
| }, | |||
| // Tempusdominus Bootstrap 4 | |||
| { | |||
| from: 'node_modules/tempusdominus-bootstrap-4/build/js', | |||
| to: 'plugins/tempusdominus-bootstrap-4/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/tempusdominus-bootstrap-4/build/css', | |||
| to: 'plugins/tempusdominus-bootstrap-4/css' | |||
| }, | |||
| // Moment | |||
| { | |||
| from: 'node_modules/moment/min', | |||
| to: 'plugins/moment' | |||
| }, | |||
| { | |||
| from: 'node_modules/moment/locale', | |||
| to: 'plugins/moment/locale' | |||
| }, | |||
| // FastClick | |||
| { | |||
| from: 'node_modules/fastclick/lib', | |||
| to: 'plugins/fastclick' | |||
| }, | |||
| // Date Range Picker | |||
| { | |||
| from: 'node_modules/daterangepicker/', | |||
| to: 'plugins/daterangepicker' | |||
| }, | |||
| // DataTables | |||
| { | |||
| from: 'node_modules/pdfmake/build', | |||
| to: 'plugins/pdfmake' | |||
| }, | |||
| { | |||
| from: 'node_modules/jszip/dist', | |||
| to: 'plugins/jszip' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net/js', | |||
| to: 'plugins/datatables' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-bs4/js', | |||
| to: 'plugins/datatables-bs4/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-bs4/css', | |||
| to: 'plugins/datatables-bs4/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-autofill/js', | |||
| to: 'plugins/datatables-autofill/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-autofill-bs4/js', | |||
| to: 'plugins/datatables-autofill/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-autofill-bs4/css', | |||
| to: 'plugins/datatables-autofill/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-buttons/js', | |||
| to: 'plugins/datatables-buttons/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-buttons-bs4/js', | |||
| to: 'plugins/datatables-buttons/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-buttons-bs4/css', | |||
| to: 'plugins/datatables-buttons/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-colreorder/js', | |||
| to: 'plugins/datatables-colreorder/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-colreorder-bs4/js', | |||
| to: 'plugins/datatables-colreorder/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-colreorder-bs4/css', | |||
| to: 'plugins/datatables-colreorder/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-fixedcolumns/js', | |||
| to: 'plugins/datatables-fixedcolumns/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-fixedcolumns-bs4/js', | |||
| to: 'plugins/datatables-fixedcolumns/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-fixedcolumns-bs4/css', | |||
| to: 'plugins/datatables-fixedcolumns/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-fixedheader/js', | |||
| to: 'plugins/datatables-fixedheader/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-fixedheader-bs4/js', | |||
| to: 'plugins/datatables-fixedheader/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-fixedheader-bs4/css', | |||
| to: 'plugins/datatables-fixedheader/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-keytable/js', | |||
| to: 'plugins/datatables-keytable/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-keytable-bs4/js', | |||
| to: 'plugins/datatables-keytable/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-keytable-bs4/css', | |||
| to: 'plugins/datatables-keytable/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-responsive/js', | |||
| to: 'plugins/datatables-responsive/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-responsive-bs4/js', | |||
| to: 'plugins/datatables-responsive/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-responsive-bs4/css', | |||
| to: 'plugins/datatables-responsive/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-rowgroup/js', | |||
| to: 'plugins/datatables-rowgroup/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-rowgroup-bs4/js', | |||
| to: 'plugins/datatables-rowgroup/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-rowgroup-bs4/css', | |||
| to: 'plugins/datatables-rowgroup/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-rowreorder/js', | |||
| to: 'plugins/datatables-rowreorder/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-rowreorder-bs4/js', | |||
| to: 'plugins/datatables-rowreorder/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-rowreorder-bs4/css', | |||
| to: 'plugins/datatables-rowreorder/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-scroller/js', | |||
| to: 'plugins/datatables-scroller/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-scroller-bs4/js', | |||
| to: 'plugins/datatables-scroller/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-scroller-bs4/css', | |||
| to: 'plugins/datatables-scroller/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-searchbuilder/js', | |||
| to: 'plugins/datatables-searchbuilder/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-searchbuilder-bs4/js', | |||
| to: 'plugins/datatables-searchbuilder/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-searchbuilder-bs4/css', | |||
| to: 'plugins/datatables-searchbuilder/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-searchpanes/js', | |||
| to: 'plugins/datatables-searchpanes/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-searchpanes-bs4/js', | |||
| to: 'plugins/datatables-searchpanes/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-searchpanes-bs4/css', | |||
| to: 'plugins/datatables-searchpanes/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-select/js', | |||
| to: 'plugins/datatables-select/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-select-bs4/js', | |||
| to: 'plugins/datatables-select/js' | |||
| }, | |||
| { | |||
| from: 'node_modules/datatables.net-select-bs4/css', | |||
| to: 'plugins/datatables-select/css' | |||
| }, | |||
| // Fullcalendar | |||
| { | |||
| from: 'node_modules/fullcalendar/', | |||
| to: 'plugins/fullcalendar' | |||
| }, | |||
| // icheck bootstrap | |||
| { | |||
| from: 'node_modules/icheck-bootstrap/', | |||
| to: 'plugins/icheck-bootstrap' | |||
| }, | |||
| // inputmask | |||
| { | |||
| from: 'node_modules/inputmask/dist/', | |||
| to: 'plugins/inputmask' | |||
| }, | |||
| // ion-rangeslider | |||
| { | |||
| from: 'node_modules/ion-rangeslider/', | |||
| to: 'plugins/ion-rangeslider' | |||
| }, | |||
| // JQVMap (jqvmap-novulnerability) | |||
| { | |||
| from: 'node_modules/jqvmap-novulnerability/dist/', | |||
| to: 'plugins/jqvmap' | |||
| }, | |||
| // jQuery Mapael | |||
| { | |||
| from: 'node_modules/jquery-mapael/js/', | |||
| to: 'plugins/jquery-mapael' | |||
| }, | |||
| // Raphael | |||
| { | |||
| from: 'node_modules/raphael/', | |||
| to: 'plugins/raphael' | |||
| }, | |||
| // jQuery Mousewheel | |||
| { | |||
| from: 'node_modules/jquery-mousewheel/', | |||
| to: 'plugins/jquery-mousewheel' | |||
| }, | |||
| // jQuery Knob | |||
| { | |||
| from: 'node_modules/jquery-knob-chif/dist/', | |||
| to: 'plugins/jquery-knob' | |||
| }, | |||
| // pace-progress | |||
| { | |||
| from: 'node_modules/@lgaitan/pace-progress/dist/', | |||
| to: 'plugins/pace-progress' | |||
| }, | |||
| // Select2 | |||
| { | |||
| from: 'node_modules/select2/dist/', | |||
| to: 'plugins/select2' | |||
| }, | |||
| { | |||
| from: 'node_modules/@ttskch/select2-bootstrap4-theme/dist/', | |||
| to: 'plugins/select2-bootstrap4-theme' | |||
| }, | |||
| // Sparklines | |||
| { | |||
| from: 'node_modules/sparklines/source/', | |||
| to: 'plugins/sparklines' | |||
| }, | |||
| // SweetAlert2 | |||
| { | |||
| from: 'node_modules/sweetalert2/dist/', | |||
| to: 'plugins/sweetalert2' | |||
| }, | |||
| { | |||
| from: 'node_modules/@sweetalert2/theme-bootstrap-4/', | |||
| to: 'plugins/sweetalert2-theme-bootstrap-4' | |||
| }, | |||
| // Toastr | |||
| { | |||
| from: 'node_modules/toastr/build/', | |||
| to: 'plugins/toastr' | |||
| }, | |||
| // jsGrid | |||
| { | |||
| from: 'node_modules/jsgrid/dist', | |||
| to: 'plugins/jsgrid' | |||
| }, | |||
| { | |||
| from: 'node_modules/jsgrid/demos/db.js', | |||
| to: 'plugins/jsgrid/demos/db.js' | |||
| }, | |||
| // flag-icon-css | |||
| { | |||
| from: 'node_modules/flag-icon-css/css', | |||
| to: 'plugins/flag-icon-css/css' | |||
| }, | |||
| { | |||
| from: 'node_modules/flag-icon-css/flags', | |||
| to: 'plugins/flag-icon-css/flags' | |||
| }, | |||
| // bootstrap4-duallistbox | |||
| { | |||
| from: 'node_modules/bootstrap4-duallistbox/dist', | |||
| to: 'plugins/bootstrap4-duallistbox/' | |||
| }, | |||
| // filterizr | |||
| { | |||
| from: 'node_modules/filterizr/dist', | |||
| to: 'plugins/filterizr/' | |||
| }, | |||
| // ekko-lightbox | |||
| { | |||
| from: 'node_modules/ekko-lightbox/dist', | |||
| to: 'plugins/ekko-lightbox/' | |||
| }, | |||
| // bootstrap-switch | |||
| { | |||
| from: 'node_modules/bootstrap-switch/dist', | |||
| to: 'plugins/bootstrap-switch/' | |||
| }, | |||
| // jQuery Validate | |||
| { | |||
| from: 'node_modules/jquery-validation/dist/', | |||
| to: 'plugins/jquery-validation' | |||
| }, | |||
| // bs-custom-file-input | |||
| { | |||
| from: 'node_modules/bs-custom-file-input/dist/', | |||
| to: 'plugins/bs-custom-file-input' | |||
| }, | |||
| // bs-stepper | |||
| { | |||
| from: 'node_modules/bs-stepper/dist/', | |||
| to: 'plugins/bs-stepper' | |||
| }, | |||
| // CodeMirror | |||
| { | |||
| from: 'node_modules/codemirror/lib/', | |||
| to: 'plugins/codemirror' | |||
| }, | |||
| { | |||
| from: 'node_modules/codemirror/addon/', | |||
| to: 'plugins/codemirror/addon' | |||
| }, | |||
| { | |||
| from: 'node_modules/codemirror/keymap/', | |||
| to: 'plugins/codemirror/keymap' | |||
| }, | |||
| { | |||
| from: 'node_modules/codemirror/mode/', | |||
| to: 'plugins/codemirror/mode' | |||
| }, | |||
| { | |||
| from: 'node_modules/codemirror/theme/', | |||
| to: 'plugins/codemirror/theme' | |||
| }, | |||
| // dropzonejs | |||
| { | |||
| from: 'node_modules/dropzone/dist/', | |||
| to: 'plugins/dropzone' | |||
| }, | |||
| // uPlot | |||
| { | |||
| from: 'node_modules/uplot/dist/', | |||
| to: 'plugins/uplot' | |||
| } | |||
| ] | |||
| module.exports = Plugins | |||
| @@ -0,0 +1,59 @@ | |||
| #!/usr/bin/env node | |||
| 'use strict' | |||
| const path = require('path') | |||
| const fse = require('fs-extra') | |||
| const Plugins = require('./Plugins') | |||
| class Publish { | |||
| constructor() { | |||
| this.options = { | |||
| verbose: false | |||
| } | |||
| this.getArguments() | |||
| } | |||
| getArguments() { | |||
| if (process.argv.length > 2) { | |||
| const arg = process.argv[2] | |||
| switch (arg) { | |||
| case '-v': | |||
| case '--verbose': | |||
| this.options.verbose = true | |||
| break | |||
| default: | |||
| throw new Error(`Unknown option ${arg}`) | |||
| } | |||
| } | |||
| } | |||
| run() { | |||
| // Publish files | |||
| Plugins.forEach(module => { | |||
| const fseOptions = { | |||
| // Skip copying dot files | |||
| filter(src) { | |||
| return !path.basename(src).startsWith('.') | |||
| } | |||
| } | |||
| try { | |||
| if (fse.existsSync(module.from)) { | |||
| fse.copySync(module.from, module.to, fseOptions) | |||
| } else { | |||
| fse.copySync(module.from.replace('node_modules/', '../'), module.to, fseOptions) | |||
| } | |||
| if (this.options.verbose) { | |||
| console.log(`Copied ${module.from} to ${module.to}`) | |||
| } | |||
| } catch (error) { | |||
| console.error(`Error: ${error}`) | |||
| } | |||
| }) | |||
| } | |||
| } | |||
| (new Publish()).run() | |||
| @@ -0,0 +1,55 @@ | |||
| #!/usr/bin/env node | |||
| /*! | |||
| * Script to run vnu-jar if Java is available. | |||
| * Copyright 2017-2021 The Bootstrap Authors | |||
| * Copyright 2017-2021 Twitter, Inc. | |||
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
| */ | |||
| 'use strict' | |||
| const childProcess = require('child_process') | |||
| const vnu = require('vnu-jar') | |||
| childProcess.exec('java -version', (error, stdout, stderr) => { | |||
| if (error) { | |||
| console.error('Skipping vnu-jar test; Java is missing.') | |||
| return | |||
| } | |||
| const is32bitJava = !/64-Bit/.test(stderr) | |||
| // vnu-jar accepts multiple ignores joined with a `|`. | |||
| // Also note that the ignores are regular expressions. | |||
| const ignores = [ | |||
| // "autocomplete" is included in <button> and checkboxes and radio <input>s due to | |||
| // Firefox's non-standard autocomplete behavior - see https://bugzilla.mozilla.org/show_bug.cgi?id=654072 | |||
| 'Attribute “autocomplete” is only allowed when the input type is.*' | |||
| ].join('|') | |||
| const args = [ | |||
| '-jar', | |||
| vnu, | |||
| '--asciiquotes', | |||
| '--skip-non-html', | |||
| // Ignore the language code warnings | |||
| '--no-langdetect', | |||
| '--Werror', | |||
| `--filterpattern "${ignores}"`, | |||
| './*.html', | |||
| 'docs_html/', | |||
| 'pages/' | |||
| ] | |||
| // For the 32-bit Java we need to pass `-Xss512k` | |||
| if (is32bitJava) { | |||
| args.splice(0, 0, '-Xss512k') | |||
| } | |||
| return childProcess.spawn('java', args, { | |||
| shell: true, | |||
| stdio: 'inherit' | |||
| }) | |||
| .on('exit', process.exit) | |||
| }) | |||
| @@ -0,0 +1,30 @@ | |||
| /*! | |||
| * AdminLTE v3.1.0 | |||
| * Author: Colorlib | |||
| * Website: AdminLTE.io <https://adminlte.io> | |||
| * License: Open source - MIT <https://opensource.org/licenses/MIT> | |||
| */ | |||
| // | |||
| // ------------------------------------------------------------------ | |||
| // This file is to be included in your custom SCSS. Before importing | |||
| // this file, you should include your custom AdminLTE and Bootstrap | |||
| // variables followed by bootstrap.scss and then this file. It's | |||
| // ok to import this file without custom variables too! | |||
| // NOTE: be sure to keep the license notice in the generated css. | |||
| // ------------------------------------------------------------------ | |||
| // | |||
| // Variables and Mixins | |||
| // --------------------------------------------------- | |||
| @import "bootstrap-variables"; | |||
| @import "variables"; | |||
| @import "variables-alt"; | |||
| @import "mixins"; | |||
| @import "parts/core"; | |||
| @import "parts/components"; | |||
| @import "parts/extra-components"; | |||
| @import "parts/pages"; | |||
| @import "parts/plugins"; | |||
| @import "parts/miscellaneous"; | |||
| @@ -0,0 +1,52 @@ | |||
| // | |||
| // Component: Alert | |||
| // | |||
| .alert { | |||
| .icon { | |||
| margin-right: 10px; | |||
| } | |||
| .close { | |||
| color: $black; | |||
| opacity: .2; | |||
| &:hover { | |||
| opacity: .5; | |||
| } | |||
| } | |||
| a { | |||
| color: $white; | |||
| text-decoration: underline; | |||
| } | |||
| } | |||
| //Alert Variants | |||
| @each $color, $value in $theme-colors { | |||
| .alert-#{$color} { | |||
| color: color-yiq($value); | |||
| background-color: $value; | |||
| border-color: darken($value, 5%); | |||
| } | |||
| .alert-default-#{$color} { | |||
| @include alert-variant(theme-color-level($color, $alert-bg-level), theme-color-level($color, $alert-border-level), theme-color-level($color, $alert-color-level)); | |||
| } | |||
| } | |||
| .dark-mode { | |||
| @each $color, $value in $theme-colors-alt { | |||
| .alert-#{$color} { | |||
| color: color-yiq($value); | |||
| background-color: $value; | |||
| border-color: darken($value, 5%); | |||
| } | |||
| .alert-default-#{$color} { | |||
| @include alert-variant(theme-color-level($color, $alert-bg-level), theme-color-level($color, $alert-border-level), theme-color-level($color, $alert-color-level)); | |||
| } | |||
| } | |||
| } | |||
| // | |||
| @@ -0,0 +1,14 @@ | |||
| // | |||
| // Component: Animation | |||
| // | |||
| .animation { | |||
| &__shake { | |||
| animation: shake 1500ms; | |||
| } | |||
| &__wobble { | |||
| animation: wobble 1500ms; | |||
| } | |||
| } | |||
| // | |||
| @@ -0,0 +1,911 @@ | |||
| // Variables | |||
| // | |||
| // Variables should follow the `$component-state-property-size` formula for | |||
| // consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs. | |||
| // | |||
| // Color system | |||
| // | |||
| // stylelint-disable | |||
| $white: #fff !default; | |||
| $gray-100: #f8f9fa !default; | |||
| $gray-200: #e9ecef !default; | |||
| $gray-300: #dee2e6 !default; | |||
| $gray-400: #ced4da !default; | |||
| $gray-500: #adb5bd !default; | |||
| $gray-600: #6c757d !default; | |||
| $gray-700: #495057 !default; | |||
| $gray-800: #343a40 !default; | |||
| $gray-900: #212529 !default; | |||
| $black: #000 !default; | |||
| $grays: () !default; | |||
| $grays: map-merge(( | |||
| "100": $gray-100, | |||
| "200": $gray-200, | |||
| "300": $gray-300, | |||
| "400": $gray-400, | |||
| "500": $gray-500, | |||
| "600": $gray-600, | |||
| "700": $gray-700, | |||
| "800": $gray-800, | |||
| "900": $gray-900 | |||
| ), $grays); | |||
| $blue: #007bff !default; | |||
| $indigo: #6610f2 !default; | |||
| $purple: #6f42c1 !default; | |||
| $pink: #e83e8c !default; | |||
| $red: #dc3545 !default; | |||
| $orange: #fd7e14 !default; | |||
| $yellow: #ffc107 !default; | |||
| $green: #28a745 !default; | |||
| $teal: #20c997 !default; | |||
| $cyan: #17a2b8 !default; | |||
| $colors: () !default; | |||
| $colors: map-merge(( | |||
| "blue": $blue, | |||
| "indigo": $indigo, | |||
| "purple": $purple, | |||
| "pink": $pink, | |||
| "red": $red, | |||
| "orange": $orange, | |||
| "yellow": $yellow, | |||
| "green": $green, | |||
| "teal": $teal, | |||
| "cyan": $cyan, | |||
| "white": $white, | |||
| "gray": $gray-600, | |||
| "gray-dark": $gray-800 | |||
| ), $colors); | |||
| $primary: $blue !default; | |||
| $secondary: $gray-600 !default; | |||
| $success: $green !default; | |||
| $info: $cyan !default; | |||
| $warning: $yellow !default; | |||
| $danger: $red !default; | |||
| $light: $gray-100 !default; | |||
| $dark: $gray-800 !default; | |||
| $theme-colors: () !default; | |||
| $theme-colors: map-merge(( | |||
| "primary": $primary, | |||
| "secondary": $secondary, | |||
| "success": $success, | |||
| "info": $info, | |||
| "warning": $warning, | |||
| "danger": $danger, | |||
| "light": $light, | |||
| "dark": $dark | |||
| ), $theme-colors); | |||
| // stylelint-enable | |||
| // Set a specific jump point for requesting color jumps | |||
| $theme-color-interval: 8% !default; | |||
| // The yiq lightness value that determines when the lightness of color changes from "dark" to "light". Acceptable values are between 0 and 255. | |||
| $yiq-contrasted-threshold: 150 !default; | |||
| // Customize the light and dark text colors for use in our YIQ color contrast function. | |||
| $yiq-text-dark: #1f2d3d !default; | |||
| $yiq-text-light: $white !default; | |||
| // Options | |||
| // | |||
| // Quickly modify global styling by enabling or disabling optional features. | |||
| $enable-caret: true !default; | |||
| $enable-rounded: true !default; | |||
| $enable-shadows: true !default; | |||
| $enable-gradients: false !default; | |||
| $enable-transitions: true !default; | |||
| $enable-prefers-reduced-motion-media-query: true !default; | |||
| $enable-hover-media-query: false !default; // Deprecated, no longer affects any compiled CSS | |||
| $enable-grid-classes: true !default; | |||
| $enable-pointer-cursor-for-buttons: true !default; | |||
| $enable-print-styles: true !default; | |||
| $enable-responsive-font-sizes: false !default; | |||
| $enable-validation-icons: true !default; | |||
| $enable-deprecation-messages: true !default; | |||
| // Spacing | |||
| // | |||
| // Control the default styling of most Bootstrap elements by modifying these | |||
| // variables. Mostly focused on spacing. | |||
| // You can add more entries to the $spacers map, should you need more variation. | |||
| // stylelint-disable | |||
| $spacer: 1rem !default; | |||
| $spacers: () !default; | |||
| $spacers: map-merge(( | |||
| 0: 0, | |||
| 1: ($spacer * .25), | |||
| 2: ($spacer * .5), | |||
| 3: $spacer, | |||
| 4: ($spacer * 1.5), | |||
| 5: ($spacer * 3) | |||
| ), $spacers); | |||
| // This variable affects the `.h-*` and `.w-*` classes. | |||
| $sizes: () !default; | |||
| $sizes: map-merge(( | |||
| 25: 25%, | |||
| 50: 50%, | |||
| 75: 75%, | |||
| 100: 100% | |||
| ), $sizes); | |||
| // stylelint-enable | |||
| // Body | |||
| // | |||
| // Settings for the `<body>` element. | |||
| $body-bg: $white !default; | |||
| $body-color: $gray-900 !default; | |||
| // Links | |||
| // | |||
| // Style anchor elements. | |||
| $link-color: theme-color("primary") !default; | |||
| $link-decoration: none !default; | |||
| $link-hover-color: darken($link-color, 15%) !default; | |||
| $link-hover-decoration: none !default; | |||
| // Paragraphs | |||
| // | |||
| // Style p element. | |||
| $paragraph-margin-bottom: 1rem !default; | |||
| // Grid breakpoints | |||
| // | |||
| // Define the minimum dimensions at which your layout will change, | |||
| // adapting to different screen sizes, for use in media queries. | |||
| $grid-breakpoints: ( | |||
| xs: 0, | |||
| sm: 576px, | |||
| md: 768px, | |||
| lg: 992px, | |||
| xl: 1200px | |||
| ) !default; | |||
| @include _assert-ascending($grid-breakpoints, "$grid-breakpoints"); | |||
| @include _assert-starts-at-zero($grid-breakpoints); | |||
| // Grid containers | |||
| // | |||
| // Define the maximum width of `.container` for different screen sizes. | |||
| $container-max-widths: ( | |||
| sm: 540px, | |||
| md: 720px, | |||
| lg: 960px, | |||
| xl: 1140px | |||
| ) !default; | |||
| @include _assert-ascending($container-max-widths, "$container-max-widths"); | |||
| // Grid columns | |||
| // | |||
| // Set the number of columns and specify the width of the gutters. | |||
| $grid-columns: 12 !default; | |||
| $grid-gutter-width: 15px !default; | |||
| // Components | |||
| // | |||
| // Define common padding and border radius sizes and more. | |||
| $line-height-lg: 1.5 !default; | |||
| $line-height-sm: 1.5 !default; | |||
| $border-width: 1px !default; | |||
| $border-color: $gray-300 !default; | |||
| $border-radius: .25rem !default; | |||
| $border-radius-lg: .3rem !default; | |||
| $border-radius-sm: .2rem !default; | |||
| $component-active-color: $white !default; | |||
| $component-active-bg: theme-color("primary") !default; | |||
| $caret-width: .3em !default; | |||
| $transition-base: all .2s ease-in-out !default; | |||
| $transition-fade: opacity .15s linear !default; | |||
| $transition-collapse: height .35s ease !default; | |||
| // Fonts | |||
| // | |||
| // Font, line-height, and color for body text, headings, and more. | |||
| // stylelint-disable value-keyword-case | |||
| $font-family-sans-serif: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default; | |||
| $font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; | |||
| $font-family-base: $font-family-sans-serif !default; | |||
| // stylelint-enable value-keyword-case | |||
| $font-size-base: 1rem !default; // Assumes the browser default, typically `16px` | |||
| $font-size-lg: ($font-size-base * 1.25) !default; | |||
| $font-size-sm: ($font-size-base * .875) !default; | |||
| $font-weight-light: 300 !default; | |||
| $font-weight-normal: 400 !default; | |||
| $font-weight-bold: 700 !default; | |||
| $font-weight-base: $font-weight-normal !default; | |||
| $line-height-base: 1.5 !default; | |||
| $h1-font-size: $font-size-base * 2.5 !default; | |||
| $h2-font-size: $font-size-base * 2 !default; | |||
| $h3-font-size: $font-size-base * 1.75 !default; | |||
| $h4-font-size: $font-size-base * 1.5 !default; | |||
| $h5-font-size: $font-size-base * 1.25 !default; | |||
| $h6-font-size: $font-size-base !default; | |||
| $headings-margin-bottom: ($spacer / 2) !default; | |||
| $headings-font-family: inherit !default; | |||
| $headings-font-weight: 500 !default; | |||
| $headings-line-height: 1.2 !default; | |||
| $headings-color: inherit !default; | |||
| $display1-size: 6rem !default; | |||
| $display2-size: 5.5rem !default; | |||
| $display3-size: 4.5rem !default; | |||
| $display4-size: 3.5rem !default; | |||
| $display1-weight: 300 !default; | |||
| $display2-weight: 300 !default; | |||
| $display3-weight: 300 !default; | |||
| $display4-weight: 300 !default; | |||
| $display-line-height: $headings-line-height !default; | |||
| $lead-font-size: ($font-size-base * 1.25) !default; | |||
| $lead-font-weight: 300 !default; | |||
| $small-font-size: 80% !default; | |||
| $text-muted: $gray-600 !default; | |||
| $blockquote-small-color: $gray-600 !default; | |||
| $blockquote-font-size: ($font-size-base * 1.25) !default; | |||
| $hr-border-color: rgba($black, .1) !default; | |||
| $hr-border-width: $border-width !default; | |||
| $mark-padding: .2em !default; | |||
| $dt-font-weight: $font-weight-bold !default; | |||
| $kbd-box-shadow: inset 0 -.1rem 0 rgba($black, .25) !default; | |||
| $nested-kbd-font-weight: $font-weight-bold !default; | |||
| $list-inline-padding: .5rem !default; | |||
| $mark-bg: #fcf8e3 !default; | |||
| $hr-margin-y: $spacer !default; | |||
| // Tables | |||
| // | |||
| // Customizes the `.table` component with basic values, each used across all table variations. | |||
| $table-cell-padding: .75rem !default; | |||
| $table-cell-padding-sm: .3rem !default; | |||
| $table-bg: transparent !default; | |||
| $table-accent-bg: rgba($black, .05) !default; | |||
| $table-hover-bg: rgba($black, .075) !default; | |||
| $table-active-bg: $table-hover-bg !default; | |||
| $table-border-width: $border-width !default; | |||
| $table-border-color: $gray-300 !default; | |||
| $table-head-bg: $gray-200 !default; | |||
| $table-head-color: $gray-700 !default; | |||
| $table-dark-bg: $gray-900 !default; | |||
| $table-dark-accent-bg: rgba($white, .05) !default; | |||
| $table-dark-hover-bg: rgba($white, .075) !default; | |||
| $table-dark-border-color: lighten($gray-900, 10%) !default; | |||
| $table-dark-color: $body-bg !default; | |||
| // Buttons + Forms | |||
| // | |||
| // Shared variables that are reassigned to `$input-` and `$btn-` specific variables. | |||
| $input-btn-padding-y: .375rem !default; | |||
| $input-btn-padding-x: .75rem !default; | |||
| $input-btn-line-height: $line-height-base !default; | |||
| $input-btn-focus-width: .2rem !default; | |||
| $input-btn-focus-color: rgba($component-active-bg, .25) !default; | |||
| $input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color !default; | |||
| $input-btn-padding-y-sm: .25rem !default; | |||
| $input-btn-padding-x-sm: .5rem !default; | |||
| $input-btn-line-height-sm: $line-height-sm !default; | |||
| $input-btn-padding-y-lg: .5rem !default; | |||
| $input-btn-padding-x-lg: 1rem !default; | |||
| $input-btn-line-height-lg: $line-height-lg !default; | |||
| $input-btn-border-width: $border-width !default; | |||
| // Buttons | |||
| // | |||
| // For each of Bootstrap's buttons, define text, background, and border color. | |||
| $btn-padding-y: $input-btn-padding-y !default; | |||
| $btn-padding-x: $input-btn-padding-x !default; | |||
| $btn-line-height: $input-btn-line-height !default; | |||
| $btn-padding-y-sm: $input-btn-padding-y-sm !default; | |||
| $btn-padding-x-sm: $input-btn-padding-x-sm !default; | |||
| $btn-line-height-sm: $input-btn-line-height-sm !default; | |||
| $btn-padding-y-lg: $input-btn-padding-y-lg !default; | |||
| $btn-padding-x-lg: $input-btn-padding-x-lg !default; | |||
| $btn-line-height-lg: $input-btn-line-height-lg !default; | |||
| $btn-border-width: $input-btn-border-width !default; | |||
| $btn-font-weight: $font-weight-normal !default; | |||
| $btn-box-shadow: none !default; | |||
| $btn-focus-width: 0 !default; | |||
| $btn-focus-box-shadow: none !default; | |||
| $btn-disabled-opacity: .65 !default; | |||
| $btn-active-box-shadow: none !default; | |||
| $btn-link-disabled-color: $gray-600 !default; | |||
| $btn-block-spacing-y: .5rem !default; | |||
| // Allows for customizing button radius independently from global border radius | |||
| $btn-border-radius: $border-radius !default; | |||
| $btn-border-radius-lg: $border-radius-lg !default; | |||
| $btn-border-radius-sm: $border-radius-sm !default; | |||
| $btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; | |||
| // Forms | |||
| $input-padding-y: $input-btn-padding-y !default; | |||
| $input-padding-x: $input-btn-padding-x !default; | |||
| $input-line-height: $input-btn-line-height !default; | |||
| $input-padding-y-sm: $input-btn-padding-y-sm !default; | |||
| $input-padding-x-sm: $input-btn-padding-x-sm !default; | |||
| $input-line-height-sm: $input-btn-line-height-sm !default; | |||
| $input-padding-y-lg: $input-btn-padding-y-lg !default; | |||
| $input-padding-x-lg: $input-btn-padding-x-lg !default; | |||
| $input-line-height-lg: $input-btn-line-height-lg !default; | |||
| $input-bg: $white !default; | |||
| $input-disabled-bg: $gray-200 !default; | |||
| $input-color: $gray-700 !default; | |||
| $input-border-color: $gray-400 !default; | |||
| $input-border-width: $input-btn-border-width !default; | |||
| $input-box-shadow: inset 0 0 0 rgba($black, 0) !default; | |||
| $input-border-radius: $border-radius !default; | |||
| $input-border-radius-lg: $border-radius-lg !default; | |||
| $input-border-radius-sm: $border-radius-sm !default; | |||
| $input-focus-bg: $input-bg !default; | |||
| $input-focus-border-color: lighten($component-active-bg, 25%) !default; | |||
| $input-focus-color: $input-color !default; | |||
| $input-focus-width: 0 !default; | |||
| $input-focus-box-shadow: none !default; | |||
| $input-placeholder-color: lighten($gray-600, 15%) !default; | |||
| $input-height-border: $input-border-width * 2 !default; | |||
| $input-height-inner: ($font-size-base * $input-btn-line-height) + ($input-btn-padding-y * 2) !default; | |||
| $input-height-inner-half: calc(#{$input-line-height * .5em} + #{$input-padding-y}) !default; | |||
| $input-height-inner-quarter: calc(#{$input-line-height * .25em} + #{$input-padding-y / 2}) !default; | |||
| $input-height: calc(#{$input-height-inner} + #{$input-height-border}) !default; | |||
| $input-height-inner-sm: ($font-size-sm * $input-btn-line-height-sm) + ($input-btn-padding-y-sm * 2) !default; | |||
| $input-height-sm: calc(#{$input-height-inner-sm} + #{$input-height-border}) !default; | |||
| $input-height-inner-lg: ($font-size-lg * $input-btn-line-height-lg) + ($input-btn-padding-y-lg * 2) !default; | |||
| $input-height-lg: calc(#{$input-height-inner-lg} + #{$input-height-border}) !default; | |||
| $input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; | |||
| $form-text-margin-top: .25rem !default; | |||
| $form-check-input-gutter: 1.25rem !default; | |||
| $form-check-input-margin-y: .3rem !default; | |||
| $form-check-input-margin-x: .25rem !default; | |||
| $form-check-inline-margin-x: .75rem !default; | |||
| $form-check-inline-input-margin-x: .3125rem !default; | |||
| $form-group-margin-bottom: 1rem !default; | |||
| $input-group-addon-color: $input-color !default; | |||
| $input-group-addon-bg: $gray-200 !default; | |||
| $input-group-addon-border-color: $input-border-color !default; | |||
| $custom-control-gutter: .5rem !default; | |||
| $custom-control-spacer-x: 1rem !default; | |||
| $custom-control-indicator-size: 1rem !default; | |||
| $custom-control-indicator-bg: $gray-300 !default; | |||
| $custom-control-indicator-bg-size: 50% 50% !default; | |||
| $custom-control-indicator-box-shadow: inset 0 .25rem .25rem rgba($black, .1) !default; | |||
| $custom-control-indicator-disabled-bg: $gray-200 !default; | |||
| $custom-control-label-disabled-color: $gray-600 !default; | |||
| $custom-control-indicator-checked-color: $component-active-color !default; | |||
| $custom-control-indicator-checked-bg: $component-active-bg !default; | |||
| $custom-control-indicator-checked-disabled-bg: rgba(theme-color("primary"), .5) !default; | |||
| $custom-control-indicator-checked-box-shadow: none !default; | |||
| $custom-control-indicator-focus-box-shadow: 0 0 0 1px $body-bg, $input-btn-focus-box-shadow !default; | |||
| $custom-control-indicator-active-color: $component-active-color !default; | |||
| $custom-control-indicator-active-bg: lighten($component-active-bg, 35%) !default; | |||
| $custom-control-indicator-active-box-shadow: none !default; | |||
| $custom-checkbox-indicator-border-radius: $border-radius !default; | |||
| $custom-checkbox-indicator-icon-checked: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='#{$custom-control-indicator-checked-color}' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E"), "#", "%23") !default; | |||
| $custom-checkbox-indicator-indeterminate-bg: $component-active-bg !default; | |||
| $custom-checkbox-indicator-indeterminate-color: $custom-control-indicator-checked-color !default; | |||
| $custom-checkbox-indicator-icon-indeterminate: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='#{$custom-checkbox-indicator-indeterminate-color}' d='M0 2h4'/%3E%3C/svg%3E"), "#", "%23") !default; | |||
| $custom-checkbox-indicator-indeterminate-box-shadow: none !default; | |||
| $custom-radio-indicator-border-radius: 50% !default; | |||
| $custom-radio-indicator-icon-checked: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='#{$custom-control-indicator-checked-color}'/%3E%3C/svg%3E"), "#", "%23") !default; | |||
| $custom-select-padding-y: .375rem !default; | |||
| $custom-select-padding-x: .75rem !default; | |||
| $custom-select-height: $input-height !default; | |||
| $custom-select-indicator-padding: 1rem !default; // Extra padding to account for the presence of the background-image based indicator | |||
| $custom-select-line-height: $input-btn-line-height !default; | |||
| $custom-select-color: $input-color !default; | |||
| $custom-select-disabled-color: $gray-600 !default; | |||
| $custom-select-bg: $white !default; | |||
| $custom-select-disabled-bg: $gray-200 !default; | |||
| $custom-select-bg-size: 8px 10px !default; // In pixels because image dimensions | |||
| $custom-select-indicator-color: $gray-800 !default; | |||
| $custom-select-indicator: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='#{$custom-select-indicator-color}' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E"), "#", "%23") !default; | |||
| $custom-select-border-width: $input-btn-border-width !default; | |||
| $custom-select-border-color: $input-border-color !default; | |||
| $custom-select-border-radius: $border-radius !default; | |||
| $custom-select-focus-border-color: $input-focus-border-color !default; | |||
| $custom-select-focus-box-shadow: none !default; | |||
| $custom-select-font-size-sm: 75% !default; | |||
| $custom-select-height-sm: $input-height-sm !default; | |||
| $custom-select-font-size-lg: 125% !default; | |||
| $custom-select-height-lg: $input-height-lg !default; | |||
| $custom-file-height: $input-height !default; | |||
| $custom-file-focus-border-color: $input-focus-border-color !default; | |||
| $custom-file-focus-box-shadow: $custom-select-focus-box-shadow !default; | |||
| $custom-file-padding-y: $input-btn-padding-y !default; | |||
| $custom-file-padding-x: $input-btn-padding-x !default; | |||
| $custom-file-line-height: $input-btn-line-height !default; | |||
| $custom-file-color: $input-color !default; | |||
| $custom-file-bg: $input-bg !default; | |||
| $custom-file-border-width: $input-btn-border-width !default; | |||
| $custom-file-border-color: $input-border-color !default; | |||
| $custom-file-border-radius: $input-border-radius !default; | |||
| $custom-file-box-shadow: $custom-select-focus-box-shadow !default; | |||
| $custom-file-button-color: $custom-file-color !default; | |||
| $custom-file-button-bg: $input-group-addon-bg !default; | |||
| $custom-file-text: ( | |||
| en: "Browse" | |||
| ) !default; | |||
| $custom-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-btn-focus-box-shadow !default; | |||
| // Form validation | |||
| $form-feedback-margin-top: $form-text-margin-top !default; | |||
| $form-feedback-font-size: $small-font-size !default; | |||
| $form-feedback-valid-color: theme-color("success") !default; | |||
| $form-feedback-invalid-color: theme-color("danger") !default; | |||
| // Dropdowns | |||
| // | |||
| // Dropdown menu container and contents. | |||
| $dropdown-min-width: 10rem !default; | |||
| $dropdown-padding-y: .5rem !default; | |||
| $dropdown-spacer: .125rem !default; | |||
| $dropdown-bg: $white !default; | |||
| $dropdown-border-color: rgba($black, .15) !default; | |||
| $dropdown-border-radius: $border-radius !default; | |||
| $dropdown-border-width: $border-width !default; | |||
| $dropdown-divider-bg: $gray-200 !default; | |||
| $dropdown-box-shadow: 0 .5rem 1rem rgba($black, .175) !default; | |||
| $dropdown-link-color: $gray-900 !default; | |||
| $dropdown-link-hover-color: darken($gray-900, 5%) !default; | |||
| $dropdown-link-hover-bg: $gray-100 !default; | |||
| $dropdown-link-active-color: $component-active-color !default; | |||
| $dropdown-link-active-bg: $component-active-bg !default; | |||
| $dropdown-link-disabled-color: $gray-600 !default; | |||
| $dropdown-item-padding-y: .25rem !default; | |||
| $dropdown-item-padding-x: 1rem !default; | |||
| $dropdown-header-color: $gray-600 !default; | |||
| // Z-index master list | |||
| // | |||
| // Warning: Avoid customizing these values. They're used for a bird's eye view | |||
| // of components dependent on the z-axis and are designed to all work together. | |||
| $zindex-dropdown: 1000 !default; | |||
| $zindex-sticky: 1020 !default; | |||
| $zindex-fixed: 1030 !default; | |||
| $zindex-modal-backdrop: 1040 !default; | |||
| $zindex-modal: 1050 !default; | |||
| $zindex-popover: 1060 !default; | |||
| $zindex-tooltip: 1070 !default; | |||
| // Navs | |||
| $nav-link-padding-y: .5rem !default; | |||
| $nav-link-padding-x: 1rem !default; | |||
| $nav-link-disabled-color: $gray-600 !default; | |||
| $nav-tabs-border-color: $gray-300 !default; | |||
| $nav-tabs-border-width: $border-width !default; | |||
| $nav-tabs-border-radius: $border-radius !default; | |||
| $nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color !default; | |||
| $nav-tabs-link-active-color: $gray-700 !default; | |||
| $nav-tabs-link-active-bg: $body-bg !default; | |||
| $nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg !default; | |||
| $nav-pills-border-radius: $border-radius !default; | |||
| $nav-pills-link-active-color: $component-active-color !default; | |||
| $nav-pills-link-active-bg: $component-active-bg !default; | |||
| // Navbar | |||
| $navbar-padding-y: ($spacer / 2) !default; | |||
| $navbar-padding-x: ($spacer / 2) !default; | |||
| $navbar-nav-link-padding-x: 1rem !default; | |||
| $navbar-brand-font-size: $font-size-lg !default; | |||
| // Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link | |||
| $nav-link-height: ($font-size-base * $line-height-base + $nav-link-padding-y * 2) !default; | |||
| $navbar-brand-height: $navbar-brand-font-size * $line-height-base !default; | |||
| $navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) / 2 !default; | |||
| $navbar-toggler-padding-y: .25rem !default; | |||
| $navbar-toggler-padding-x: .75rem !default; | |||
| $navbar-toggler-font-size: $font-size-lg !default; | |||
| $navbar-toggler-border-radius: $btn-border-radius !default; | |||
| $navbar-dark-color: rgba($white, .75) !default; | |||
| $navbar-dark-hover-color: rgba($white, 1) !default; | |||
| $navbar-dark-active-color: $white !default; | |||
| $navbar-dark-disabled-color: rgba($white, .25) !default; | |||
| $navbar-dark-toggler-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='#{$navbar-dark-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"), "#", "%23") !default; | |||
| $navbar-dark-toggler-border-color: rgba($white, .1) !default; | |||
| $navbar-light-color: rgba($black, .5) !default; | |||
| $navbar-light-hover-color: rgba($black, .7) !default; | |||
| $navbar-light-active-color: rgba($black, .9) !default; | |||
| $navbar-light-disabled-color: rgba($black, .3) !default; | |||
| $navbar-light-toggler-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='#{$navbar-light-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"), "#", "%23") !default; | |||
| $navbar-light-toggler-border-color: rgba($black, .1) !default; | |||
| // Pagination | |||
| $pagination-padding-y: .5rem !default; | |||
| $pagination-padding-x: .75rem !default; | |||
| $pagination-padding-y-sm: .25rem !default; | |||
| $pagination-padding-x-sm: .5rem !default; | |||
| $pagination-padding-y-lg: .75rem !default; | |||
| $pagination-padding-x-lg: 1.5rem !default; | |||
| $pagination-line-height: 1.25 !default; | |||
| $pagination-color: $link-color !default; | |||
| $pagination-bg: $white !default; | |||
| $pagination-border-width: $border-width !default; | |||
| $pagination-border-color: $gray-300 !default; | |||
| $pagination-focus-box-shadow: $input-btn-focus-box-shadow !default; | |||
| $pagination-hover-color: $link-hover-color !default; | |||
| $pagination-hover-bg: $gray-200 !default; | |||
| $pagination-hover-border-color: $gray-300 !default; | |||
| $pagination-active-color: $component-active-color !default; | |||
| $pagination-active-bg: $component-active-bg !default; | |||
| $pagination-active-border-color: $pagination-active-bg !default; | |||
| $pagination-disabled-color: $gray-600 !default; | |||
| $pagination-disabled-bg: $white !default; | |||
| $pagination-disabled-border-color: $gray-300 !default; | |||
| // Jumbotron | |||
| $jumbotron-padding: 2rem !default; | |||
| $jumbotron-bg: $gray-200 !default; | |||
| // Cards | |||
| $card-spacer-y: .75rem !default; | |||
| $card-spacer-x: 1.25rem !default; | |||
| $card-border-width: 0 !default; //$border-width !default; | |||
| $card-border-radius: $border-radius !default; | |||
| $card-border-color: rgba($black, .125) !default; | |||
| $card-inner-border-radius: calc(#{$card-border-radius} - #{$card-border-width}) !default; | |||
| $card-cap-bg: rgba($black, .03) !default; | |||
| $card-bg: $white !default; | |||
| $card-img-overlay-padding: 1.25rem !default; | |||
| $card-group-margin: ($grid-gutter-width / 2) !default; | |||
| $card-deck-margin: $card-group-margin !default; | |||
| $card-columns-count: 3 !default; | |||
| $card-columns-gap: 1.25rem !default; | |||
| $card-columns-margin: $card-spacer-y !default; | |||
| // Tooltips | |||
| $tooltip-font-size: $font-size-sm !default; | |||
| $tooltip-max-width: 200px !default; | |||
| $tooltip-color: $white !default; | |||
| $tooltip-bg: $black !default; | |||
| $tooltip-border-radius: $border-radius !default; | |||
| $tooltip-opacity: .9 !default; | |||
| $tooltip-padding-y: .25rem !default; | |||
| $tooltip-padding-x: .5rem !default; | |||
| $tooltip-margin: 0 !default; | |||
| $tooltip-arrow-width: .8rem !default; | |||
| $tooltip-arrow-height: .4rem !default; | |||
| $tooltip-arrow-color: $tooltip-bg !default; | |||
| // Form tooltips must come after regular tooltips | |||
| $form-feedback-tooltip-padding-y: $tooltip-padding-y !default; | |||
| $form-feedback-tooltip-padding-x: $tooltip-padding-x !default; | |||
| $form-feedback-tooltip-font-size: $tooltip-font-size !default; | |||
| $form-feedback-tooltip-line-height: $line-height-base !default; | |||
| $form-feedback-tooltip-opacity: $tooltip-opacity !default; | |||
| $form-feedback-tooltip-border-radius: $tooltip-border-radius !default; | |||
| // Popovers | |||
| $popover-font-size: $font-size-sm !default; | |||
| $popover-bg: $white !default; | |||
| $popover-max-width: 276px !default; | |||
| $popover-border-width: $border-width !default; | |||
| $popover-border-color: rgba($black, .2) !default; | |||
| $popover-border-radius: $border-radius-lg !default; | |||
| $popover-box-shadow: 0 .25rem .5rem rgba($black, .2) !default; | |||
| $popover-header-bg: darken($popover-bg, 3%) !default; | |||
| $popover-header-color: $headings-color !default; | |||
| $popover-header-padding-y: .5rem !default; | |||
| $popover-header-padding-x: .75rem !default; | |||
| $popover-body-color: $body-color !default; | |||
| $popover-body-padding-y: $popover-header-padding-y !default; | |||
| $popover-body-padding-x: $popover-header-padding-x !default; | |||
| $popover-arrow-width: 1rem !default; | |||
| $popover-arrow-height: .5rem !default; | |||
| $popover-arrow-color: $popover-bg !default; | |||
| $popover-arrow-outer-color: fade-in($popover-border-color, .05) !default; | |||
| // Badges | |||
| $badge-font-size: 75% !default; | |||
| $badge-font-weight: $font-weight-bold !default; | |||
| $badge-padding-y: .25em !default; | |||
| $badge-padding-x: .4em !default; | |||
| $badge-border-radius: $border-radius !default; | |||
| $badge-pill-padding-x: .6em !default; | |||
| // Use a higher than normal value to ensure completely rounded edges when | |||
| // customizing padding or font-size on labels. | |||
| $badge-pill-border-radius: 10rem !default; | |||
| // Modals | |||
| // Padding applied to the modal body | |||
| $modal-inner-padding: 1rem !default; | |||
| $modal-dialog-margin: .5rem !default; | |||
| $modal-dialog-margin-y-sm-up: 1.75rem !default; | |||
| $modal-title-line-height: $line-height-base !default; | |||
| $modal-content-bg: $white !default; | |||
| $modal-content-border-color: rgba($black, .2) !default; | |||
| $modal-content-border-width: $border-width !default; | |||
| $modal-content-border-radius: $border-radius-lg !default; | |||
| $modal-content-box-shadow-xs: 0 .25rem .5rem rgba($black, .5) !default; | |||
| $modal-content-box-shadow-sm-up: 0 .5rem 1rem rgba($black, .5) !default; | |||
| $modal-backdrop-bg: $black !default; | |||
| $modal-backdrop-opacity: .5 !default; | |||
| $modal-header-border-color: $gray-200 !default; | |||
| $modal-footer-border-color: $modal-header-border-color !default; | |||
| $modal-header-border-width: $modal-content-border-width !default; | |||
| $modal-footer-border-width: $modal-header-border-width !default; | |||
| $modal-header-padding: 1rem !default; | |||
| $modal-lg: 800px !default; | |||
| $modal-md: 500px !default; | |||
| $modal-sm: 300px !default; | |||
| $modal-transition: transform .3s ease-out !default; | |||
| // Alerts | |||
| // | |||
| // Define alert colors, border radius, and padding. | |||
| $alert-padding-y: .75rem !default; | |||
| $alert-padding-x: 1.25rem !default; | |||
| $alert-margin-bottom: 1rem !default; | |||
| $alert-border-radius: $border-radius !default; | |||
| $alert-link-font-weight: $font-weight-bold !default; | |||
| $alert-border-width: $border-width !default; | |||
| $alert-bg-level: -10 !default; | |||
| $alert-border-level: -9 !default; | |||
| $alert-color-level: 6 !default; | |||
| // Progress bars | |||
| $progress-height: 1rem !default; | |||
| $progress-font-size: ($font-size-base * .75) !default; | |||
| $progress-bg: $gray-200 !default; | |||
| $progress-border-radius: $border-radius !default; | |||
| $progress-box-shadow: inset 0 .1rem .1rem rgba($black, .1) !default; | |||
| $progress-bar-color: $white !default; | |||
| $progress-bar-bg: theme-color("primary") !default; | |||
| $progress-bar-animation-timing: 1s linear infinite !default; | |||
| $progress-bar-transition: width .6s ease !default; | |||
| // List group | |||
| $list-group-bg: $white !default; | |||
| $list-group-border-color: rgba($black, .125) !default; | |||
| $list-group-border-width: $border-width !default; | |||
| $list-group-border-radius: $border-radius !default; | |||
| $list-group-item-padding-y: .75rem !default; | |||
| $list-group-item-padding-x: 1.25rem !default; | |||
| $list-group-hover-bg: $gray-100 !default; | |||
| $list-group-active-color: $component-active-color !default; | |||
| $list-group-active-bg: $component-active-bg !default; | |||
| $list-group-active-border-color: $list-group-active-bg !default; | |||
| $list-group-disabled-color: $gray-600 !default; | |||
| $list-group-disabled-bg: $list-group-bg !default; | |||
| $list-group-action-color: $gray-700 !default; | |||
| $list-group-action-hover-color: $list-group-action-color !default; | |||
| $list-group-action-active-color: $body-color !default; | |||
| $list-group-action-active-bg: $gray-200 !default; | |||
| // Image thumbnails | |||
| $thumbnail-padding: .25rem !default; | |||
| $thumbnail-bg: $body-bg !default; | |||
| $thumbnail-border-width: $border-width !default; | |||
| $thumbnail-border-color: $gray-300 !default; | |||
| $thumbnail-border-radius: $border-radius !default; | |||
| $thumbnail-box-shadow: 0 1px 2px rgba($black, .075) !default; | |||
| // Figures | |||
| $figure-caption-font-size: 90% !default; | |||
| $figure-caption-color: $gray-600 !default; | |||
| // Breadcrumbs | |||
| $breadcrumb-padding-y: .75rem !default; | |||
| $breadcrumb-padding-x: 1rem !default; | |||
| $breadcrumb-item-padding: .5rem !default; | |||
| $breadcrumb-margin-bottom: 1rem !default; | |||
| $breadcrumb-bg: $gray-200 !default; | |||
| $breadcrumb-divider-color: $gray-600 !default; | |||
| $breadcrumb-active-color: $gray-600 !default; | |||
| $breadcrumb-divider: "/" !default; | |||
| // Carousel | |||
| $carousel-control-color: $white !default; | |||
| $carousel-control-width: 15% !default; | |||
| $carousel-control-opacity: .5 !default; | |||
| $carousel-indicator-width: 30px !default; | |||
| $carousel-indicator-height: 3px !default; | |||
| $carousel-indicator-spacer: 3px !default; | |||
| $carousel-indicator-active-bg: $white !default; | |||
| $carousel-caption-width: 70% !default; | |||
| $carousel-caption-color: $white !default; | |||
| $carousel-control-icon-width: 20px !default; | |||
| $carousel-control-prev-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E"), "#", "%23") !default; | |||
| $carousel-control-next-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E"), "#", "%23") !default; | |||
| $carousel-transition: transform .6s ease !default; | |||
| // Close | |||
| $close-font-size: $font-size-base * 1.5 !default; | |||
| $close-font-weight: $font-weight-bold !default; | |||
| $close-color: $black !default; | |||
| $close-text-shadow: 0 1px 0 $white !default; | |||
| // Code | |||
| $code-font-size: 87.5% !default; | |||
| $code-color: $pink !default; | |||
| $kbd-padding-y: .2rem !default; | |||
| $kbd-padding-x: .4rem !default; | |||
| $kbd-font-size: $code-font-size !default; | |||
| $kbd-color: $white !default; | |||
| $kbd-bg: $gray-900 !default; | |||
| $pre-color: $gray-900 !default; | |||
| $pre-scrollable-max-height: 340px !default; | |||
| // Printing | |||
| $print-page-size: a3 !default; | |||
| $print-body-min-width: map-get($grid-breakpoints, "lg") !default; | |||
| @@ -0,0 +1,106 @@ | |||
| // | |||
| // Component: Brand | |||
| // | |||
| .brand-link { | |||
| $brand-link-padding-y: $navbar-brand-padding-y + $navbar-padding-y; | |||
| display: block; | |||
| font-size: $navbar-brand-font-size; | |||
| line-height: $line-height-lg; | |||
| padding: $brand-link-padding-y $sidebar-padding-x; | |||
| transition: width $transition-speed $transition-fn; | |||
| white-space: nowrap; | |||
| &:hover { | |||
| color: $white; | |||
| text-decoration: none; | |||
| } | |||
| .text-sm & { | |||
| font-size: inherit; | |||
| } | |||
| [class*="sidebar-dark"] & { | |||
| border-bottom: 1px solid lighten($dark, 10%); | |||
| &, | |||
| .pushmenu { | |||
| color: rgba($white, .8); | |||
| &:hover { | |||
| color: $white; | |||
| } | |||
| } | |||
| } | |||
| [class*="sidebar-light"] & { | |||
| border-bottom: 1px solid $gray-300; | |||
| &, | |||
| .pushmenu { | |||
| color: rgba($black, .8); | |||
| &:hover { | |||
| color: $black; | |||
| } | |||
| } | |||
| } | |||
| .pushmenu { | |||
| margin-right: $sidebar-padding-x; | |||
| font-size: $font-size-base; | |||
| } | |||
| .brand-link { | |||
| padding: 0; | |||
| border-bottom: none; | |||
| } | |||
| .brand-image { | |||
| float: left; | |||
| line-height: .8; | |||
| margin-left: .8rem; | |||
| margin-right: .5rem; | |||
| margin-top: -3px; | |||
| max-height: 33px; | |||
| width: auto; | |||
| } | |||
| .brand-image-xs { | |||
| float: left; | |||
| line-height: .8; | |||
| margin-top: -.1rem; | |||
| max-height: 33px; | |||
| width: auto; | |||
| } | |||
| .brand-image-xl { | |||
| line-height: .8; | |||
| max-height: 40px; | |||
| width: auto; | |||
| &.single { | |||
| margin-top: -.3rem; | |||
| } | |||
| } | |||
| &.text-sm, | |||
| .text-sm & { | |||
| .brand-image { | |||
| height: 29px; | |||
| margin-bottom: -.25rem; | |||
| margin-left: .95rem; | |||
| margin-top: -.25rem; | |||
| } | |||
| .brand-image-xs { | |||
| margin-top: -.2rem; | |||
| max-height: 29px; | |||
| } | |||
| .brand-image-xl { | |||
| margin-top: -.225rem; | |||
| max-height: 38px; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,154 @@ | |||
| // | |||
| // Component: Button | |||
| // | |||
| .btn { | |||
| &.disabled, | |||
| &:disabled { | |||
| cursor: not-allowed; | |||
| } | |||
| // Flat buttons | |||
| &.btn-flat { | |||
| @include border-radius(0); | |||
| border-width: 1px; | |||
| box-shadow: none; | |||
| } | |||
| // input file btn | |||
| &.btn-file { | |||
| overflow: hidden; | |||
| position: relative; | |||
| > input[type="file"] { | |||
| background-color: $white; | |||
| cursor: inherit; | |||
| display: block; | |||
| font-size: 100px; | |||
| min-height: 100%; | |||
| min-width: 100%; | |||
| opacity: 0; | |||
| outline: none; | |||
| position: absolute; | |||
| right: 0; | |||
| text-align: right; | |||
| top: 0; | |||
| } | |||
| } | |||
| .text-sm & { | |||
| font-size: $font-size-sm !important; | |||
| } | |||
| } | |||
| // Button color variations | |||
| .btn-default { | |||
| background-color: $button-default-background-color; | |||
| border-color: $button-default-border-color; | |||
| color: $button-default-color; | |||
| &:hover, | |||
| &:active, | |||
| &.hover { | |||
| background-color: darken($button-default-background-color, 5%); | |||
| color: darken($button-default-color, 10%); | |||
| } | |||
| } | |||
| // Application buttons | |||
| .btn-app { | |||
| @include border-radius(3px); | |||
| background-color: $button-default-background-color; | |||
| border: 1px solid $button-default-border-color; | |||
| color: $gray-600; | |||
| font-size: 12px; | |||
| height: 60px; | |||
| margin: 0 0 10px 10px; | |||
| min-width: 80px; | |||
| padding: 15px 5px; | |||
| position: relative; | |||
| text-align: center; | |||
| // Icons within the btn | |||
| > .fa, | |||
| > .fas, | |||
| > .far, | |||
| > .fab, | |||
| > .fal, | |||
| > .fad, | |||
| > .svg-inline--fa, | |||
| > .ion { | |||
| display: block; | |||
| font-size: 20px; | |||
| } | |||
| > .svg-inline--fa { | |||
| margin: 0 auto; | |||
| } | |||
| &:hover { | |||
| background-color: $button-default-background-color; | |||
| border-color: darken($button-default-border-color, 20%); | |||
| color: $button-default-color; | |||
| } | |||
| &:active, | |||
| &:focus { | |||
| @include box-shadow(inset 0 3px 5px rgba($black, .125)); | |||
| } | |||
| // The badge | |||
| > .badge { | |||
| font-size: 10px; | |||
| font-weight: 400; | |||
| position: absolute; | |||
| right: -10px; | |||
| top: -3px; | |||
| } | |||
| } | |||
| // Extra Button Size | |||
| .btn-xs { | |||
| @include button-size($button-padding-y-xs, $button-padding-x-xs, $button-font-size-xs, $button-line-height-xs, $button-border-radius-xs); | |||
| } | |||
| .dark-mode { | |||
| .btn-default, | |||
| .btn-app { | |||
| background-color: lighten($dark, 2.5%); | |||
| color: $white; | |||
| border-color: $gray-600; | |||
| &:hover, | |||
| &:focus { | |||
| background-color: lighten($dark, 5%); | |||
| color: $gray-300; | |||
| border-color: lighten($gray-600, 2.5%); | |||
| } | |||
| } | |||
| .btn-light { | |||
| background-color: lighten($dark, 7.5%); | |||
| color: $white; | |||
| border-color: $gray-600; | |||
| &:hover, | |||
| &:focus { | |||
| background-color: lighten($dark, 10%); | |||
| color: $gray-300; | |||
| border-color: lighten($gray-600, 5%); | |||
| } | |||
| } | |||
| @each $color, $value in $theme-colors-alt { | |||
| .btn-#{$color} { | |||
| @include button-variant($value, $value); | |||
| } | |||
| } | |||
| @each $color, $value in $theme-colors-alt { | |||
| .btn-outline-#{$color} { | |||
| @include button-outline-variant($value); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,73 @@ | |||
| // | |||
| // Component: Callout | |||
| // | |||
| // Base styles (regardless of theme) | |||
| .callout { | |||
| @if $enable-rounded { | |||
| @include border-radius($border-radius); | |||
| } | |||
| @if $enable-shadows { | |||
| box-shadow: map-get($elevations, 1); | |||
| } @else { | |||
| border: 1px solid $gray-300; | |||
| } | |||
| background-color: $white; | |||
| border-left: 5px solid $gray-200; | |||
| margin-bottom: map-get($spacers, 3); | |||
| padding: 1rem; | |||
| a { | |||
| color: $gray-700; | |||
| text-decoration: underline; | |||
| &:hover { | |||
| color: $gray-200; | |||
| } | |||
| } | |||
| p:last-child { | |||
| margin-bottom: 0; | |||
| } | |||
| // Themes for different contexts | |||
| &.callout-danger { | |||
| border-left-color: darken(theme-color("danger"), 10%); | |||
| } | |||
| &.callout-warning { | |||
| border-left-color: darken(theme-color("warning"), 10%); | |||
| } | |||
| &.callout-info { | |||
| border-left-color: darken(theme-color("info"), 10%); | |||
| } | |||
| &.callout-success { | |||
| border-left-color: darken(theme-color("success"), 10%); | |||
| } | |||
| } | |||
| .dark-mode { | |||
| .callout { | |||
| background-color: lighten($dark, 5%); | |||
| &.callout-danger { | |||
| border-left-color: lighten($danger-alt, 10%); | |||
| } | |||
| &.callout-warning { | |||
| border-left-color: lighten($warning-alt, 10%); | |||
| } | |||
| &.callout-info { | |||
| border-left-color: lighten($info-alt, 10%); | |||
| } | |||
| &.callout-success { | |||
| border-left-color: lighten($success-alt, 10%); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,545 @@ | |||
| // | |||
| // Component: Cards | |||
| // | |||
| // Color variants | |||
| @each $name, $color in $theme-colors { | |||
| @include cards-variant($name, $color); | |||
| } | |||
| @each $name, $color in $colors { | |||
| @include cards-variant($name, $color); | |||
| } | |||
| .card { | |||
| @include box-shadow($card-shadow); | |||
| margin-bottom: map-get($spacers, 3); | |||
| &.bg-dark { | |||
| .card-header { | |||
| border-color: $card-dark-border-color; | |||
| } | |||
| &, | |||
| .card-body { | |||
| color: $white; | |||
| } | |||
| } | |||
| &.maximized-card { | |||
| height: 100% !important; | |||
| left: 0; | |||
| max-height: 100% !important; | |||
| max-width: 100% !important; | |||
| position: fixed; | |||
| top: 0; | |||
| width: 100% !important; | |||
| z-index: $zindex-modal-backdrop; | |||
| &.was-collapsed .card-body { | |||
| display: block !important; | |||
| } | |||
| .card-body { | |||
| overflow: auto; | |||
| } | |||
| [data-card-widgett="collapse"] { | |||
| display: none; | |||
| } | |||
| .card-header, | |||
| .card-footer { | |||
| @include border-radius(0 !important); | |||
| } | |||
| } | |||
| // collapsed mode | |||
| &.collapsed-card { | |||
| .card-body, | |||
| .card-footer { | |||
| display: none; | |||
| } | |||
| } | |||
| .nav.flex-column { | |||
| > li { | |||
| border-bottom: 1px solid $card-border-color; | |||
| margin: 0; | |||
| &:last-of-type { | |||
| border-bottom: 0; | |||
| } | |||
| } | |||
| } | |||
| // fixed height to 300px | |||
| &.height-control { | |||
| .card-body { | |||
| max-height: 300px; | |||
| overflow: auto; | |||
| } | |||
| } | |||
| .border-right { | |||
| border-right: 1px solid $card-border-color; | |||
| } | |||
| .border-left { | |||
| border-left: 1px solid $card-border-color; | |||
| } | |||
| &.card-tabs { | |||
| &:not(.card-outline) { | |||
| > .card-header { | |||
| border-bottom: 0; | |||
| .nav-item { | |||
| &:first-child .nav-link { | |||
| border-left-color: transparent; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| &.card-outline { | |||
| .nav-item { | |||
| border-bottom: 0; | |||
| &:first-child .nav-link { | |||
| border-left: 0; | |||
| margin-left: 0; | |||
| } | |||
| } | |||
| } | |||
| .card-tools { | |||
| margin: .3rem .5rem; | |||
| } | |||
| &:not(.expanding-card).collapsed-card { | |||
| .card-header { | |||
| border-bottom: 0; | |||
| .nav-tabs { | |||
| border-bottom: 0; | |||
| .nav-item { | |||
| margin-bottom: 0; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| &.expanding-card { | |||
| .card-header { | |||
| .nav-tabs { | |||
| .nav-item { | |||
| margin-bottom: -1px; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| &.card-outline-tabs { | |||
| border-top: 0; | |||
| .card-header { | |||
| .nav-item { | |||
| &:first-child .nav-link { | |||
| border-left: 0; | |||
| margin-left: 0; | |||
| } | |||
| } | |||
| a { | |||
| border-top: 3px solid transparent; | |||
| &:hover { | |||
| border-top: 3px solid $nav-tabs-border-color; | |||
| } | |||
| &.active { | |||
| &:hover { | |||
| margin-top: 0; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .card-tools { | |||
| margin: .5rem .5rem .3rem; | |||
| } | |||
| &:not(.expanding-card).collapsed-card .card-header { | |||
| border-bottom: 0; | |||
| .nav-tabs { | |||
| border-bottom: 0; | |||
| .nav-item { | |||
| margin-bottom: 0; | |||
| } | |||
| } | |||
| } | |||
| &.expanding-card { | |||
| .card-header { | |||
| .nav-tabs { | |||
| .nav-item { | |||
| margin-bottom: -1px; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // Maximized Card Body Scroll fix | |||
| html.maximized-card { | |||
| overflow: hidden; | |||
| } | |||
| // Add clearfix to header, body and footer | |||
| .card-header, | |||
| .card-body, | |||
| .card-footer { | |||
| @include clearfix (); | |||
| } | |||
| // Box header | |||
| .card-header { | |||
| background-color: transparent; | |||
| border-bottom: 1px solid $card-border-color; | |||
| padding: (($card-spacer-y / 2) * 2) $card-spacer-x; | |||
| position: relative; | |||
| @if $enable-rounded { | |||
| @include border-top-radius($border-radius); | |||
| } | |||
| .collapsed-card & { | |||
| border-bottom: 0; | |||
| } | |||
| > .card-tools { | |||
| float: right; | |||
| margin-right: -$card-spacer-x / 2; | |||
| .input-group, | |||
| .nav, | |||
| .pagination { | |||
| margin-bottom: -$card-spacer-y / 2.5; | |||
| margin-top: -$card-spacer-y / 2.5; | |||
| } | |||
| [data-toggle="tooltip"] { | |||
| position: relative; | |||
| } | |||
| } | |||
| } | |||
| .card-title { | |||
| float: left; | |||
| font-size: $card-title-font-size; | |||
| font-weight: $card-title-font-weight; | |||
| margin: 0; | |||
| } | |||
| .card-text { | |||
| clear: both; | |||
| } | |||
| // Box Tools Buttons | |||
| .btn-tool { | |||
| background-color: transparent; | |||
| color: $gray-500; | |||
| font-size: $font-size-sm; | |||
| margin: -(($card-spacer-y / 2) * 2) 0; | |||
| padding: .25rem .5rem; | |||
| .btn-group.show &, | |||
| &:hover { | |||
| color: $gray-700; | |||
| } | |||
| .show &, | |||
| &:focus { | |||
| box-shadow: none !important; | |||
| } | |||
| } | |||
| .text-sm { | |||
| .card-title { | |||
| font-size: $card-title-font-size-sm; | |||
| } | |||
| .nav-link { | |||
| padding: $card-nav-link-padding-sm-y $card-nav-link-padding-sm-x; | |||
| } | |||
| } | |||
| // Box Body | |||
| .card-body { | |||
| // @include border-radius-sides(0, 0, $border-radius, $border-radius); | |||
| // .no-header & { | |||
| // @include border-top-radius($border-radius); | |||
| // } | |||
| // Tables within the box body | |||
| > .table { | |||
| margin-bottom: 0; | |||
| > thead > tr > th, | |||
| > thead > tr > td { | |||
| border-top-width: 0; | |||
| } | |||
| } | |||
| // Calendar within the box body | |||
| .fc { | |||
| margin-top: 5px; | |||
| } | |||
| .full-width-chart { | |||
| margin: -19px; | |||
| } | |||
| &.p-0 .full-width-chart { | |||
| margin: -9px; | |||
| } | |||
| } | |||
| .chart-legend { | |||
| @include list-unstyled (); | |||
| margin: 10px 0; | |||
| > li { | |||
| @media (max-width: map-get($grid-breakpoints, sm)) { | |||
| float: left; | |||
| margin-right: 10px; | |||
| } | |||
| } | |||
| } | |||
| // Comment Box | |||
| .card-comments { | |||
| background-color: $gray-100; | |||
| .card-comment { | |||
| @include clearfix (); | |||
| border-bottom: 1px solid $gray-200; | |||
| padding: 8px 0; | |||
| &:last-of-type { | |||
| border-bottom: 0; | |||
| } | |||
| &:first-of-type { | |||
| padding-top: 0; | |||
| } | |||
| img { | |||
| height: $card-img-size; | |||
| width: $card-img-size; | |||
| float: left; | |||
| } | |||
| } | |||
| .comment-text { | |||
| color: lighten($gray-700, 20%); | |||
| margin-left: 40px; | |||
| } | |||
| .username { | |||
| color: $gray-700; | |||
| display: block; | |||
| font-weight: 600; | |||
| } | |||
| .text-muted { | |||
| font-size: 12px; | |||
| font-weight: 400; | |||
| } | |||
| } | |||
| // Widgets | |||
| //----------- | |||
| // Widget: TODO LIST | |||
| .todo-list { | |||
| list-style: none; | |||
| margin: 0; | |||
| overflow: auto; | |||
| padding: 0; | |||
| // Todo list element | |||
| > li { | |||
| @include border-radius(2px); | |||
| background-color: $gray-100; | |||
| border-left: 2px solid $gray-200; | |||
| color: $gray-700; | |||
| margin-bottom: 2px; | |||
| padding: 10px; | |||
| &:last-of-type { | |||
| margin-bottom: 0; | |||
| } | |||
| > input[type="checkbox"] { | |||
| margin: 0 10px 0 5px; | |||
| } | |||
| .text { | |||
| display: inline-block; | |||
| font-weight: 600; | |||
| margin-left: 5px; | |||
| } | |||
| // Time labels | |||
| .badge { | |||
| font-size: .7rem; | |||
| margin-left: 10px; | |||
| } | |||
| // Tools and options box | |||
| .tools { | |||
| color: theme-color("danger"); | |||
| display: none; | |||
| float: right; | |||
| // icons | |||
| > .fa, | |||
| > .fas, | |||
| > .far, | |||
| > .fab, | |||
| > .fal, | |||
| > .fad, | |||
| > .svg-inline--fa, | |||
| > .ion { | |||
| cursor: pointer; | |||
| margin-right: 5px; | |||
| } | |||
| } | |||
| &:hover .tools { | |||
| display: inline-block; | |||
| } | |||
| &.done { | |||
| color: darken($gray-500, 25%); | |||
| .text { | |||
| font-weight: 500; | |||
| text-decoration: line-through; | |||
| } | |||
| .badge { | |||
| background-color: $gray-500 !important; | |||
| } | |||
| } | |||
| } | |||
| // Color variants | |||
| @each $name, $color in $theme-colors { | |||
| .#{$name} { | |||
| border-left-color: $color; | |||
| } | |||
| } | |||
| @each $name, $color in $colors { | |||
| .#{$name} { | |||
| border-left-color: $color; | |||
| } | |||
| } | |||
| .handle { | |||
| cursor: move; | |||
| display: inline-block; | |||
| margin: 0 5px; | |||
| } | |||
| } | |||
| // END TODO WIDGET | |||
| // Input in box | |||
| .card-input { | |||
| max-width: 200px; | |||
| } | |||
| // Nav Tabs override | |||
| .card-default { | |||
| .nav-item { | |||
| &:first-child .nav-link { | |||
| border-left: 0; | |||
| } | |||
| } | |||
| } | |||
| .dark-mode { | |||
| // Color variants | |||
| @each $name, $color in $theme-colors-alt { | |||
| @include cards-variant($name, $color); | |||
| } | |||
| @each $name, $color in $colors-alt { | |||
| @include cards-variant($name, $color); | |||
| } | |||
| .card { | |||
| background-color: $dark; | |||
| color: $white; | |||
| .card { | |||
| background-color: lighten($dark, 5%); | |||
| color: $white; | |||
| } | |||
| .nav.flex-column > li { | |||
| border-bottom-color: $gray-600; | |||
| } | |||
| .card-footer { | |||
| background-color: rgba($black, .1); | |||
| } | |||
| &.card-outline-tabs .card-header a:hover { | |||
| border-color: $gray-600; | |||
| border-bottom-color: transparent; | |||
| } | |||
| &:not(.card-outline) > .card-header a.active { | |||
| color: $white; | |||
| } | |||
| } | |||
| .card-comments { | |||
| background-color: lighten($dark, 1.25%); | |||
| .username { | |||
| color: $gray-400; | |||
| } | |||
| .card-comment { | |||
| border-bottom-color: lighten($dark, 7.5%); | |||
| } | |||
| } | |||
| .todo-list > li { | |||
| background-color: lighten($dark, 5%); | |||
| border-color: lighten($dark, 7.5%); | |||
| color: $white; | |||
| } | |||
| .todo-list { | |||
| @each $name, $color in $theme-colors-alt { | |||
| .#{$name} { | |||
| border-left-color: $color; | |||
| } | |||
| } | |||
| @each $name, $color in $colors-alt { | |||
| .#{$name} { | |||
| border-left-color: $color; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,28 @@ | |||
| // | |||
| // Component: Carousel | |||
| // | |||
| .carousel-control-custom-icon { | |||
| .carousel-control-prev & { | |||
| margin-left: -20px; | |||
| } | |||
| .carousel-control-next & { | |||
| margin-right: 20px; | |||
| } | |||
| > .fa, | |||
| > .fas, | |||
| > .far, | |||
| > .fab, | |||
| > .fal, | |||
| > .fad, | |||
| > .svg-inline--fa, | |||
| > .ion { | |||
| display: inline-block; | |||
| font-size: 40px; | |||
| margin-top: -20px; | |||
| position: absolute; | |||
| top: 50%; | |||
| z-index: 5; | |||
| } | |||
| } | |||
| @@ -0,0 +1,44 @@ | |||
| .close { | |||
| float: right; | |||
| @include font-size($close-font-size); | |||
| font-weight: $close-font-weight; | |||
| line-height: 1; | |||
| color: $close-color; | |||
| text-shadow: $close-text-shadow; | |||
| opacity: .5; | |||
| // Override <a>'s hover style | |||
| @include hover() { | |||
| color: $close-color; | |||
| text-decoration: none; | |||
| } | |||
| &:not(:disabled):not(.disabled) { | |||
| @include hover-focus() { | |||
| opacity: .75; | |||
| } | |||
| } | |||
| &:focus { | |||
| outline: none; | |||
| } | |||
| } | |||
| // Additional properties for button version | |||
| // iOS requires the button element instead of an anchor tag. | |||
| // If you want the anchor version, it requires `href="#"`. | |||
| // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile | |||
| // stylelint-disable-next-line selector-no-qualifying-type | |||
| button.close { | |||
| padding: 0; | |||
| background-color: transparent; | |||
| border: 0; | |||
| } | |||
| // Future-proof disabling of clicks on `<a>` elements | |||
| // stylelint-disable-next-line selector-no-qualifying-type | |||
| a.close.disabled { | |||
| pointer-events: none; | |||
| } | |||
| @@ -0,0 +1,144 @@ | |||
| // | |||
| // Misc: Colors | |||
| // | |||
| // Background colors (theme colors) | |||
| @each $name, $color in $theme-colors { | |||
| @include background-variant($name, $color); | |||
| } | |||
| // Background colors (colors) | |||
| @each $name, $color in $colors { | |||
| @include background-variant($name, $color); | |||
| } | |||
| .bg-gray { | |||
| background-color: $gray-500; | |||
| color: color-yiq($gray-500); | |||
| } | |||
| .bg-gray-light { | |||
| background-color: lighten($gray-200, 3%); | |||
| color: color-yiq(lighten($gray-200, 3%)) !important; | |||
| } | |||
| .bg-black { | |||
| background-color: $black; | |||
| color: color-yiq($black) !important; | |||
| } | |||
| .bg-white { | |||
| background-color: $white; | |||
| color: color-yiq($white) !important; | |||
| } | |||
| // Gradient Background colors (theme colors) | |||
| @each $name, $color in $theme-colors { | |||
| @include background-gradient-variant($name, $color); | |||
| } | |||
| // Gradient Background colors (colors) | |||
| @each $name, $color in $colors { | |||
| @include background-gradient-variant($name, $color); | |||
| } | |||
| // Backgrund Color Disabled | |||
| [class^="bg-"].disabled { | |||
| opacity: .65; | |||
| } | |||
| // Text muted hover | |||
| a.text-muted:hover { | |||
| color: theme-color(primary) !important; | |||
| } | |||
| // Link Styles | |||
| .link-muted { | |||
| color: darken($gray-500, 30%); | |||
| &:hover, | |||
| &:focus { | |||
| color: darken($gray-500, 40%); | |||
| } | |||
| } | |||
| .link-black { | |||
| color: $gray-600; | |||
| &:hover, | |||
| &:focus { | |||
| color: lighten($gray-500, 20%); | |||
| } | |||
| } | |||
| // Accent colors (theme colors) | |||
| @each $name, $color in $theme-colors { | |||
| @include accent-variant($name, $color); | |||
| } | |||
| // Accent colors (colors) | |||
| @each $name, $color in $colors { | |||
| @include accent-variant($name, $color); | |||
| } | |||
| // Accent button override fix | |||
| [class*="accent-"] { | |||
| @each $name, $color in $theme-colors { | |||
| a.btn-#{$name} { | |||
| color: color-yiq($color); | |||
| } | |||
| } | |||
| } | |||
| .dark-mode { | |||
| .bg-light { | |||
| background-color: lighten($dark, 7.5%) !important; | |||
| color: $white !important; | |||
| } | |||
| .text-black, | |||
| .text-dark, | |||
| .link-black, | |||
| .link-dark { | |||
| color: $gray-400; | |||
| } | |||
| // Background colors (theme colors) | |||
| @each $name, $color in $theme-colors-alt { | |||
| @include background-variant($name, $color); | |||
| } | |||
| // Background colors (colors) | |||
| @each $name, $color in $colors-alt { | |||
| @include background-variant($name, $color); | |||
| } | |||
| // Gradient Background colors (theme colors) | |||
| @each $name, $color in $theme-colors-alt { | |||
| @include background-gradient-variant($name, $color); | |||
| } | |||
| // Gradient Background colors (colors) | |||
| @each $name, $color in $colors-alt { | |||
| @include background-gradient-variant($name, $color); | |||
| } | |||
| // Accent colors (theme colors) | |||
| @each $name, $color in $theme-colors-alt { | |||
| @include accent-variant($name, $color); | |||
| } | |||
| [class*="accent-"] { | |||
| @each $name, $color in $theme-colors-alt { | |||
| a.btn-#{$name} { | |||
| color: color-yiq($color); | |||
| } | |||
| } | |||
| } | |||
| // Accent colors (colors) | |||
| @each $name, $color in $colors-alt { | |||
| @include accent-variant($name, $color); | |||
| } | |||
| } | |||
| // | |||
| @@ -0,0 +1,173 @@ | |||
| // | |||
| // Component: Control Sidebar | |||
| // | |||
| html.control-sidebar-animate { | |||
| overflow-x: hidden; | |||
| } | |||
| .control-sidebar { | |||
| bottom: $main-footer-height; | |||
| position: absolute; | |||
| top: $main-header-height; | |||
| z-index: $zindex-control-sidebar; | |||
| &, | |||
| &::before { | |||
| bottom: $main-footer-height; | |||
| display: none; | |||
| right: -$control-sidebar-width; | |||
| width: $control-sidebar-width; | |||
| @include transition(right $transition-speed $transition-fn, display $transition-speed $transition-fn); | |||
| } | |||
| &::before { | |||
| content: ""; | |||
| display: block; | |||
| position: fixed; | |||
| top: 0; | |||
| z-index: -1; | |||
| } | |||
| } | |||
| body.text-sm { | |||
| .control-sidebar { | |||
| bottom: $main-footer-height-sm; | |||
| top: $main-header-height-sm; | |||
| } | |||
| } | |||
| .main-header.text-sm ~ .control-sidebar { | |||
| top: $main-header-height-sm; | |||
| } | |||
| .main-footer.text-sm ~ .control-sidebar { | |||
| bottom: $main-footer-height-sm; | |||
| } | |||
| .control-sidebar-push-slide { | |||
| .content-wrapper, | |||
| .main-footer { | |||
| @include transition(margin-right $transition-speed $transition-fn); | |||
| } | |||
| } | |||
| // Control sidebar open state | |||
| .control-sidebar-open { | |||
| .control-sidebar { | |||
| display: block; | |||
| &, | |||
| &::before { | |||
| right: 0; | |||
| } | |||
| } | |||
| &.control-sidebar-push, | |||
| &.control-sidebar-push-slide { | |||
| .content-wrapper, | |||
| .main-footer { | |||
| margin-right: $control-sidebar-width; | |||
| } | |||
| } | |||
| } | |||
| // Control sidebar slide over content state | |||
| .control-sidebar-slide-open { | |||
| .control-sidebar { | |||
| display: block; | |||
| &, | |||
| &::before { | |||
| right: 0; | |||
| @include transition(right $transition-speed $transition-fn, display $transition-speed $transition-fn); | |||
| } | |||
| } | |||
| &.control-sidebar-push, | |||
| &.control-sidebar-push-slide { | |||
| .content-wrapper, | |||
| .main-footer { | |||
| margin-right: $control-sidebar-width; | |||
| } | |||
| } | |||
| } | |||
| // Dark skin | |||
| .control-sidebar-dark { | |||
| background-color: $sidebar-dark-bg; | |||
| &, | |||
| a, | |||
| .nav-link { | |||
| color: $sidebar-dark-color; | |||
| } | |||
| a:hover { | |||
| color: $sidebar-dark-hover-color; | |||
| } | |||
| // Headers and labels | |||
| h1, | |||
| h2, | |||
| h3, | |||
| h4, | |||
| h5, | |||
| h6, | |||
| label { | |||
| color: $sidebar-dark-hover-color; | |||
| } | |||
| // Tabs | |||
| .nav-tabs { | |||
| background-color: $sidebar-dark-hover-bg; | |||
| border-bottom: 0; | |||
| margin-bottom: 5px; | |||
| .nav-item { | |||
| margin: 0; | |||
| } | |||
| .nav-link { | |||
| border-radius: 0; | |||
| padding: 10px 20px; | |||
| position: relative; | |||
| text-align: center; | |||
| &, | |||
| &:hover, | |||
| &:active, | |||
| &:focus, | |||
| &.active { | |||
| border: 0; | |||
| } | |||
| &:hover, | |||
| &:active, | |||
| &:focus, | |||
| &.active { | |||
| border-bottom-color: transparent; | |||
| border-left-color: transparent; | |||
| border-top-color: transparent; | |||
| color: $sidebar-dark-hover-color; | |||
| } | |||
| &.active { | |||
| background-color: $sidebar-dark-bg; | |||
| } | |||
| } | |||
| } | |||
| .tab-pane { | |||
| padding: 10px 15px; | |||
| } | |||
| } | |||
| // Light skin | |||
| .control-sidebar-light { | |||
| color: lighten($sidebar-light-color, 10%); | |||
| // Background | |||
| background-color: $sidebar-light-bg; | |||
| border-left: $main-header-bottom-border; | |||
| } | |||
| @@ -0,0 +1,259 @@ | |||
| // | |||
| // Component: Direct Chat | |||
| // | |||
| .direct-chat { | |||
| .card-body { | |||
| overflow-x: hidden; | |||
| padding: 0; | |||
| position: relative; | |||
| } | |||
| &.chat-pane-open { | |||
| .direct-chat-contacts { | |||
| @include translate(0, 0); | |||
| } | |||
| } | |||
| &.timestamp-light { | |||
| .direct-chat-timestamp { | |||
| color: lighten(color-yiq($yiq-text-light), 10%); | |||
| } | |||
| } | |||
| &.timestamp-dark { | |||
| .direct-chat-timestamp { | |||
| color: darken(color-yiq($yiq-text-dark), 20%); | |||
| } | |||
| } | |||
| } | |||
| .direct-chat-messages { | |||
| @include translate(0, 0); | |||
| height: 250px; | |||
| overflow: auto; | |||
| padding: 10px; | |||
| } | |||
| .direct-chat-msg, | |||
| .direct-chat-text { | |||
| display: block; | |||
| } | |||
| .direct-chat-msg { | |||
| @include clearfix (); | |||
| margin-bottom: 10px; | |||
| } | |||
| .direct-chat-messages, | |||
| .direct-chat-contacts { | |||
| transition: transform .5s ease-in-out; | |||
| } | |||
| .direct-chat-text { | |||
| @if $enable-rounded { | |||
| @include border-radius($border-radius-lg); | |||
| } | |||
| background-color: $direct-chat-default-msg-bg; | |||
| border: 1px solid $direct-chat-default-msg-border-color; | |||
| color: $direct-chat-default-font-color; | |||
| margin: 5px 0 0 50px; | |||
| padding: 5px 10px; | |||
| position: relative; | |||
| //Create the arrow | |||
| &::after, | |||
| &::before { | |||
| border: solid transparent; | |||
| border-right-color: $direct-chat-default-msg-border-color; | |||
| content: " "; | |||
| height: 0; | |||
| pointer-events: none; | |||
| position: absolute; | |||
| right: 100%; | |||
| top: 15px; | |||
| width: 0; | |||
| } | |||
| &::after { | |||
| border-width: 5px; | |||
| margin-top: -5px; | |||
| } | |||
| &::before { | |||
| border-width: 6px; | |||
| margin-top: -6px; | |||
| } | |||
| .right & { | |||
| margin-left: 0; | |||
| margin-right: 50px; | |||
| &::after, | |||
| &::before { | |||
| border-left-color: $direct-chat-default-msg-border-color; | |||
| border-right-color: transparent; | |||
| left: 100%; | |||
| right: auto; | |||
| } | |||
| } | |||
| } | |||
| .direct-chat-img { | |||
| @include border-radius(50%); | |||
| float: left; | |||
| height: 40px; | |||
| width: 40px; | |||
| .right & { | |||
| float: right; | |||
| } | |||
| } | |||
| .direct-chat-infos { | |||
| display: block; | |||
| font-size: $font-size-sm; | |||
| margin-bottom: 2px; | |||
| } | |||
| .direct-chat-name { | |||
| font-weight: 600; | |||
| } | |||
| .direct-chat-timestamp { | |||
| color: darken($gray-500, 25%); | |||
| } | |||
| //Direct chat contacts pane | |||
| .direct-chat-contacts-open { | |||
| .direct-chat-contacts { | |||
| @include translate(0, 0); | |||
| } | |||
| } | |||
| .direct-chat-contacts { | |||
| @include translate(101%, 0); | |||
| background-color: $dark; | |||
| bottom: 0; | |||
| color: $white; | |||
| height: 250px; | |||
| overflow: auto; | |||
| position: absolute; | |||
| top: 0; | |||
| width: 100%; | |||
| } | |||
| .direct-chat-contacts-light { | |||
| background-color: $light; | |||
| .contacts-list-name { | |||
| color: $gray-700; | |||
| } | |||
| .contacts-list-date { | |||
| color: $gray-600; | |||
| } | |||
| .contacts-list-msg { | |||
| color: darken($gray-600, 10%); | |||
| } | |||
| } | |||
| //Contacts list -- for displaying contacts in direct chat contacts pane | |||
| .contacts-list { | |||
| @include list-unstyled (); | |||
| > li { | |||
| @include clearfix (); | |||
| border-bottom: 1px solid rgba($black, .2); | |||
| margin: 0; | |||
| padding: 10px; | |||
| &:last-of-type { | |||
| border-bottom: 0; | |||
| } | |||
| } | |||
| } | |||
| .contacts-list-img { | |||
| @include border-radius(50%); | |||
| float: left; | |||
| width: 40px; | |||
| } | |||
| .contacts-list-info { | |||
| color: $white; | |||
| margin-left: 45px; | |||
| } | |||
| .contacts-list-name, | |||
| .contacts-list-status { | |||
| display: block; | |||
| } | |||
| .contacts-list-name { | |||
| font-weight: 600; | |||
| } | |||
| .contacts-list-status { | |||
| font-size: $font-size-sm; | |||
| } | |||
| .contacts-list-date { | |||
| color: $gray-400; | |||
| font-weight: 400; | |||
| } | |||
| .contacts-list-msg { | |||
| color: darken($gray-400, 10%); | |||
| } | |||
| // Color variants | |||
| @each $name, $color in $theme-colors { | |||
| .direct-chat-#{$name} { | |||
| @include direct-chat-variant($color); | |||
| } | |||
| } | |||
| @each $name, $color in $colors { | |||
| .direct-chat-#{$name} { | |||
| @include direct-chat-variant($color); | |||
| } | |||
| } | |||
| .dark-mode { | |||
| .direct-chat-text { | |||
| background-color: lighten($dark, 7.5%); | |||
| border-color: lighten($dark, 10%); | |||
| color: $white; | |||
| &::after, | |||
| &::before { | |||
| border-right-color: lighten($dark, 10%); | |||
| } | |||
| } | |||
| .direct-chat-timestamp { | |||
| color: $gray-500; | |||
| } | |||
| .right > .direct-chat-text { | |||
| &::after, | |||
| &::before { | |||
| border-right-color: transparent; | |||
| } | |||
| } | |||
| // Color variants | |||
| @each $name, $color in $theme-colors-alt { | |||
| .direct-chat-#{$name} { | |||
| @include direct-chat-variant($color); | |||
| } | |||
| } | |||
| @each $name, $color in $colors-alt { | |||
| .direct-chat-#{$name} { | |||
| @include direct-chat-variant($color); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,295 @@ | |||
| // | |||
| // Component: Dropdown | |||
| // | |||
| // General Dropdown Rules | |||
| //.dropdown-item { | |||
| // &:first-of-type { | |||
| // @include border-top-radius($border-radius); | |||
| // } | |||
| // &:last-of-type { | |||
| // @include border-bottom-radius($border-radius); | |||
| // } | |||
| //} | |||
| .text-sm { | |||
| .dropdown-menu { | |||
| font-size: $font-size-sm !important; | |||
| } | |||
| .dropdown-toggle::after { | |||
| vertical-align: .2rem; | |||
| } | |||
| } | |||
| .dropdown-item-title { | |||
| font-size: $font-size-base; | |||
| margin: 0; | |||
| } | |||
| .dropdown-icon { | |||
| &::after { | |||
| margin-left: 0; | |||
| } | |||
| } | |||
| // Dropdown Sizes | |||
| .dropdown-menu-lg { | |||
| max-width: 300px; | |||
| min-width: 280px; | |||
| padding: 0; | |||
| .dropdown-divider { | |||
| margin: 0; | |||
| } | |||
| .dropdown-item { | |||
| padding: $dropdown-padding-y $dropdown-item-padding-x; | |||
| } | |||
| p { | |||
| margin: 0; | |||
| white-space: normal; | |||
| } | |||
| } | |||
| // Dropdown Submenu | |||
| .dropdown-submenu { | |||
| position: relative; | |||
| > a::after { | |||
| @include caret-right (); | |||
| float: right; | |||
| margin-left: .5rem; | |||
| margin-top: .5rem; | |||
| } | |||
| > .dropdown-menu { | |||
| left: 100%; | |||
| margin-left: 0; | |||
| margin-top: 0; | |||
| top: 0; | |||
| } | |||
| } | |||
| // Dropdown Hover | |||
| .dropdown-hover { | |||
| &:hover, | |||
| &.nav-item.dropdown:hover, | |||
| .dropdown-submenu:hover, | |||
| &.dropdown-submenu:hover { | |||
| > .dropdown-menu { | |||
| display: block; | |||
| } | |||
| } | |||
| } | |||
| // Dropdown Sizes | |||
| .dropdown-menu-xl { | |||
| max-width: 420px; | |||
| min-width: 360px; | |||
| padding: 0; | |||
| .dropdown-divider { | |||
| margin: 0; | |||
| } | |||
| .dropdown-item { | |||
| padding: $dropdown-padding-y $dropdown-item-padding-x; | |||
| } | |||
| p { | |||
| margin: 0; | |||
| white-space: normal; | |||
| } | |||
| } | |||
| // Dropdown header and footer | |||
| .dropdown-footer, | |||
| .dropdown-header { | |||
| display: block; | |||
| font-size: $font-size-sm; | |||
| padding: .5rem $dropdown-item-padding-x; | |||
| text-align: center; | |||
| } | |||
| // Add fade animation to dropdown menus by appending | |||
| // the class .animated-dropdown-menu to the .dropdown-menu ul (or ol) | |||
| .open:not(.dropup) > .animated-dropdown-menu { | |||
| @include animation(flipInX .7s both); | |||
| backface-visibility: visible !important; | |||
| } | |||
| // Fix dropdown menu in navbars | |||
| .navbar-custom-menu > .navbar-nav { | |||
| > li { | |||
| position: relative; | |||
| > .dropdown-menu { | |||
| position: absolute; | |||
| right: 0; | |||
| left: auto; | |||
| } | |||
| } | |||
| } | |||
| @include media-breakpoint-down(sm) { | |||
| .navbar-custom-menu > .navbar-nav { | |||
| float: right; | |||
| > li { | |||
| position: static; | |||
| > .dropdown-menu { | |||
| position: absolute; | |||
| right: 5%; | |||
| left: auto; | |||
| border: 1px solid #ddd; | |||
| background-color: $white; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // User Menu | |||
| .navbar-nav > .user-menu { | |||
| > .nav-link::after { | |||
| content: none; | |||
| } | |||
| > .dropdown-menu { | |||
| @include border-top-radius(0); | |||
| padding: 0; | |||
| width: 280px; | |||
| &, | |||
| > .user-body { | |||
| @include border-bottom-radius(4px); | |||
| } | |||
| // Header menu | |||
| > li.user-header { | |||
| height: 175px; | |||
| padding: 10px; | |||
| text-align: center; | |||
| // User image | |||
| > img { | |||
| z-index: 5; | |||
| height: 90px; | |||
| width: 90px; | |||
| border: 3px solid; | |||
| border-color: transparent; | |||
| border-color: rgba(255, 255, 255, .2); | |||
| } | |||
| > p { | |||
| z-index: 5; | |||
| font-size: 17px; | |||
| //text-shadow: 2px 2px 3px #333333; | |||
| margin-top: 10px; | |||
| > small { | |||
| display: block; | |||
| font-size: 12px; | |||
| } | |||
| } | |||
| } | |||
| // Menu Body | |||
| > .user-body { | |||
| @include clearfix (); | |||
| border-bottom: 1px solid $gray-700; | |||
| border-top: 1px solid $gray-300; | |||
| padding: 15px; | |||
| a { | |||
| @include media-breakpoint-up(sm) { | |||
| background-color: $white !important; | |||
| color: $gray-700 !important; | |||
| } | |||
| } | |||
| } | |||
| // Menu Footer | |||
| > .user-footer { | |||
| @include clearfix (); | |||
| background-color: $gray-100; | |||
| padding: 10px; | |||
| .btn-default { | |||
| color: $gray-600; | |||
| &:hover { | |||
| @include media-breakpoint-up(sm) { | |||
| background-color: $gray-100; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .user-image { | |||
| @include media-breakpoint-up(sm) { | |||
| float: none; | |||
| line-height: 10px; | |||
| margin-right: .4rem; | |||
| margin-top: -8px; | |||
| } | |||
| border-radius: 50%; | |||
| float: left; | |||
| height: $sidebar-user-image-width; | |||
| margin-right: 10px; | |||
| margin-top: -2px; | |||
| width: $sidebar-user-image-width; | |||
| } | |||
| } | |||
| .dark-mode { | |||
| .dropdown-menu { | |||
| background-color: $dark; | |||
| color: $white; | |||
| } | |||
| .dropdown-item { | |||
| color: $white; | |||
| &:focus, | |||
| &:hover { | |||
| background-color: lighten($dark, 5%); | |||
| } | |||
| } | |||
| .dropdown-divider { | |||
| border-color: $gray-600; | |||
| } | |||
| .navbar-nav > .user-menu > .dropdown-menu { | |||
| > .user-footer { | |||
| background-color: lighten($dark, 2.5%); | |||
| color: $white; | |||
| .btn-default { | |||
| color: $white; | |||
| &:hover, | |||
| &:focus { | |||
| background-color: lighten($dark, 5%); | |||
| color: $gray-300; | |||
| } | |||
| &:focus { | |||
| background-color: lighten($dark, 7.5%); | |||
| } | |||
| } | |||
| } | |||
| > .user-body { | |||
| border-color: $gray-600; | |||
| } | |||
| > .user-body a { | |||
| background-color: transparent !important; | |||
| color: $white !important; | |||
| &:hover, | |||
| &:focus { | |||
| color: $gray-400 !important; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,14 @@ | |||
| // | |||
| // Component: Elevation | |||
| // | |||
| .elevation-0 { | |||
| box-shadow: none !important; | |||
| } | |||
| // Background colors (colors) | |||
| @each $name, $value in $elevations { | |||
| .elevation-#{$name} { | |||
| box-shadow: $value !important; | |||
| } | |||
| } | |||
| @@ -0,0 +1,431 @@ | |||
| // | |||
| // Component: Forms | |||
| // | |||
| .form-group { | |||
| &.has-icon { | |||
| position: relative; | |||
| .form-control { | |||
| padding-right: 35px; | |||
| } | |||
| .form-icon { | |||
| background-color: transparent; | |||
| border: 0; | |||
| cursor: pointer; | |||
| font-size: 1rem; | |||
| // margin-top: -3px; | |||
| padding: $input-btn-padding-y $input-btn-padding-x; | |||
| position: absolute; | |||
| right: 3px; | |||
| top: 0; | |||
| } | |||
| } | |||
| } | |||
| // Button groups | |||
| .btn-group-vertical { | |||
| .btn { | |||
| &.btn-flat:first-of-type, | |||
| &.btn-flat:last-of-type { | |||
| @include border-radius(0); | |||
| } | |||
| } | |||
| } | |||
| // Support icons in form-control | |||
| .form-control-feedback { | |||
| &.fa, | |||
| &.fas, | |||
| &.far, | |||
| &.fab, | |||
| &.fal, | |||
| &.fad, | |||
| &.svg-inline--fa, | |||
| &.ion { | |||
| line-height: $input-height; | |||
| } | |||
| } | |||
| .input-lg + .form-control-feedback, | |||
| .input-group-lg + .form-control-feedback { | |||
| &.fa, | |||
| &.fas, | |||
| &.far, | |||
| &.fab, | |||
| &.fal, | |||
| &.fad, | |||
| &.svg-inline--fa, | |||
| &.ion { | |||
| line-height: $input-height-lg; | |||
| } | |||
| } | |||
| .form-group-lg { | |||
| .form-control + .form-control-feedback { | |||
| &.fa, | |||
| &.fas, | |||
| &.far, | |||
| &.fab, | |||
| &.fal, | |||
| &.fad, | |||
| &.svg-inline--fa, | |||
| &.ion { | |||
| line-height: $input-height-lg; | |||
| } | |||
| } | |||
| } | |||
| .input-sm + .form-control-feedback, | |||
| .input-group-sm + .form-control-feedback { | |||
| &.fa, | |||
| &.fas, | |||
| &.far, | |||
| &.fab, | |||
| &.fal, | |||
| &.fad, | |||
| &.svg-inline--fa, | |||
| &.ion { | |||
| line-height: $input-height-sm; | |||
| } | |||
| } | |||
| .form-group-sm { | |||
| .form-control + .form-control-feedback { | |||
| &.fa, | |||
| &.fas, | |||
| &.far, | |||
| &.fab, | |||
| &.fal, | |||
| &.fad, | |||
| &.svg-inline--fa, | |||
| &.ion { | |||
| line-height: $input-height-sm; | |||
| } | |||
| } | |||
| } | |||
| label:not(.form-check-label):not(.custom-file-label) { | |||
| font-weight: $font-weight-bold; | |||
| } | |||
| .warning-feedback { | |||
| @include font-size($form-feedback-font-size); | |||
| color: theme-color("warning"); | |||
| display: none; | |||
| margin-top: $form-feedback-margin-top; | |||
| width: 100%; | |||
| } | |||
| .warning-tooltip { | |||
| @include border-radius($form-feedback-tooltip-border-radius); | |||
| @include font-size($form-feedback-tooltip-font-size); | |||
| background-color: rgba(theme-color("warning"), $form-feedback-tooltip-opacity); | |||
| color: color-yiq(theme-color("warning")); | |||
| display: none; | |||
| line-height: $form-feedback-tooltip-line-height; | |||
| margin-top: .1rem; | |||
| max-width: 100%; // Contain to parent when possible | |||
| padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x; | |||
| position: absolute; | |||
| top: 100%; | |||
| z-index: 5; | |||
| } | |||
| .form-control { | |||
| &.is-warning { | |||
| border-color: theme-color("warning"); | |||
| @if $enable-validation-icons { | |||
| // padding-right: $input-height-inner; | |||
| // background-image: none; | |||
| // background-repeat: no-repeat; | |||
| // background-position: center right $input-height-inner-quarter; | |||
| // background-size: $input-height-inner-half $input-height-inner-half; | |||
| } | |||
| &:focus { | |||
| border-color: theme-color("warning"); | |||
| box-shadow: 0 0 0 $input-focus-width rgba(theme-color("warning"), .25); | |||
| } | |||
| ~ .warning-feedback, | |||
| ~ .warning-tooltip { | |||
| display: block; | |||
| } | |||
| } | |||
| } | |||
| // stylelint-disable-next-line selector-no-qualifying-type | |||
| textarea.form-control { | |||
| &.is-warning { | |||
| @if $enable-validation-icons { | |||
| padding-right: $input-height-inner; | |||
| background-position: top $input-height-inner-quarter right $input-height-inner-quarter; | |||
| } | |||
| } | |||
| } | |||
| .custom-select { | |||
| &.is-warning { | |||
| border-color: theme-color("warning"); | |||
| @if $enable-validation-icons { | |||
| // padding-right: $custom-select-feedback-icon-padding-right; | |||
| // background: $custom-select-background, none $custom-select-bg no-repeat $custom-select-feedback-icon-position / $custom-select-feedback-icon-size; | |||
| } | |||
| &:focus { | |||
| border-color: theme-color("warning"); | |||
| box-shadow: 0 0 0 $input-focus-width rgba(theme-color("warning"), .25); | |||
| } | |||
| ~ .warning-feedback, | |||
| ~ .warning-tooltip { | |||
| display: block; | |||
| } | |||
| } | |||
| } | |||
| .form-control-file { | |||
| &.is-warning { | |||
| ~ .warning-feedback, | |||
| ~ .warning-tooltip { | |||
| display: block; | |||
| } | |||
| } | |||
| } | |||
| .form-check-input { | |||
| &.is-warning { | |||
| ~ .form-check-label { | |||
| color: theme-color("warning"); | |||
| } | |||
| ~ .warning-feedback, | |||
| ~ .warning-tooltip { | |||
| display: block; | |||
| } | |||
| } | |||
| } | |||
| .custom-control-input.is-warning { | |||
| ~ .custom-control-label { | |||
| color: theme-color("warning"); | |||
| &::before { | |||
| border-color: theme-color("warning"); | |||
| } | |||
| } | |||
| ~ .warning-feedback, | |||
| ~ .warning-tooltip { | |||
| display: block; | |||
| } | |||
| &:checked { | |||
| ~ .custom-control-label::before { | |||
| @include gradient-bg(lighten(theme-color("warning"), 10%)); | |||
| border-color: lighten(theme-color("warning"), 10%); | |||
| } | |||
| } | |||
| &:focus { | |||
| ~ .custom-control-label::before { | |||
| box-shadow: 0 0 0 $input-focus-width rgba(theme-color("warning"), .25); | |||
| } | |||
| &:not(:checked) ~ .custom-control-label::before { | |||
| border-color: theme-color("warning"); | |||
| } | |||
| } | |||
| } | |||
| // custom file | |||
| .custom-file-input { | |||
| &.is-warning { | |||
| ~ .custom-file-label { | |||
| border-color: theme-color("warning"); | |||
| } | |||
| ~ .warning-feedback, | |||
| ~ .warning-tooltip { | |||
| display: block; | |||
| } | |||
| &:focus { | |||
| ~ .custom-file-label { | |||
| border-color: theme-color("warning"); | |||
| box-shadow: 0 0 0 $input-focus-width rgba(theme-color("warning"), .25); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // body.text-sm support | |||
| body.text-sm { | |||
| .input-group-text { | |||
| font-size: $font-size-sm; | |||
| } | |||
| } | |||
| // custom .form-control styles | |||
| .form-control, | |||
| .custom-select { | |||
| &.form-control-border { | |||
| border-top: 0; | |||
| border-left: 0; | |||
| border-right: 0; | |||
| border-radius: 0; | |||
| box-shadow: inherit; | |||
| &.border-width-2 { | |||
| border-bottom-width: 2px; | |||
| } | |||
| &.border-width-3 { | |||
| border-bottom-width: 3px; | |||
| } | |||
| } | |||
| } | |||
| // custom switch color variations | |||
| .custom-switch { | |||
| @each $name, $color in $theme-colors { | |||
| @include custom-switch-variant($name, $color); | |||
| } | |||
| @each $name, $color in $colors { | |||
| @include custom-switch-variant($name, $color); | |||
| } | |||
| } | |||
| // custom range color variations | |||
| .custom-range { | |||
| @each $name, $color in $theme-colors { | |||
| @include custom-range-variant($name, $color); | |||
| } | |||
| @each $name, $color in $colors { | |||
| @include custom-range-variant($name, $color); | |||
| } | |||
| } | |||
| // custom control input variations | |||
| @each $name, $color in $theme-colors { | |||
| @include custom-control-input-variant($name, $color); | |||
| } | |||
| @each $name, $color in $colors { | |||
| @include custom-control-input-variant($name, $color); | |||
| } | |||
| .custom-control-input-outline { | |||
| ~ .custom-control-label::before { | |||
| background-color: transparent !important; | |||
| box-shadow: none; | |||
| } | |||
| &:checked ~ .custom-control-label::before { | |||
| @include gradient-bg(transparent); | |||
| } | |||
| } | |||
| .navbar-dark { | |||
| .btn-navbar, | |||
| .form-control-navbar { | |||
| background-color: lighten($sidebar-dark-bg, 5%); | |||
| border: 1px solid lighten($sidebar-dark-bg, 15%); | |||
| color: lighten(color-yiq(lighten($sidebar-dark-bg, 5%)), 15%); | |||
| } | |||
| .btn-navbar { | |||
| &:hover { | |||
| background-color: lighten($sidebar-dark-bg, 7.5%); | |||
| } | |||
| &:focus { | |||
| background-color: lighten($sidebar-dark-bg, 10%); | |||
| } | |||
| } | |||
| .form-control-navbar + .input-group-prepend, | |||
| .form-control-navbar + .input-group-append { | |||
| > .btn-navbar { | |||
| background-color: lighten($sidebar-dark-bg, 5%); | |||
| color: $white; | |||
| border: 1px solid lighten($sidebar-dark-bg, 15%); | |||
| border-left: none; | |||
| } | |||
| } | |||
| } | |||
| .dark-mode { | |||
| .form-control:not(.form-control-navbar):not(.form-control-sidebar), | |||
| .custom-select, | |||
| .custom-file-label, | |||
| .custom-file-label::after, | |||
| .custom-control-label::before, | |||
| .input-group-text { | |||
| background-color: $dark; | |||
| color: $white; | |||
| } | |||
| .form-control:not(.form-control-navbar):not(.form-control-sidebar):not(.is-invalid):not(:focus), | |||
| .custom-file-label, | |||
| .custom-file-label::after { | |||
| border-color: $gray-600; | |||
| } | |||
| select { | |||
| background-color: $dark; | |||
| color: $white; | |||
| border-color: $gray-600; | |||
| } | |||
| .input-group-text { | |||
| border-color: $gray-600; | |||
| } | |||
| .custom-control-input:disabled ~ .custom-control-label::before, | |||
| .custom-control-input[disabled] ~ .custom-control-label::before { | |||
| background-color: lighten($dark, 5%); | |||
| border-color: $gray-600; | |||
| color: $white; | |||
| } | |||
| .custom-range { | |||
| &::-webkit-slider-runnable-track { | |||
| background-color: lighten($dark, 7.5%); | |||
| } | |||
| &::-moz-range-track { | |||
| background-color: lighten($dark, 7.5%); | |||
| } | |||
| &::-ms-track { | |||
| background-color: lighten($dark, 7.5%); | |||
| } | |||
| @each $name, $color in $theme-colors-alt { | |||
| @include custom-range-variant($name, $color); | |||
| } | |||
| @each $name, $color in $colors-alt { | |||
| @include custom-range-variant($name, $color); | |||
| } | |||
| } | |||
| // custom switch color variations | |||
| .custom-switch { | |||
| @each $name, $color in $theme-colors-alt { | |||
| @include custom-switch-variant($name, $color); | |||
| } | |||
| @each $name, $color in $colors-alt { | |||
| @include custom-switch-variant($name, $color); | |||
| } | |||
| } | |||
| @each $name, $color in $theme-colors-alt { | |||
| @include custom-control-input-variant($name, $color); | |||
| } | |||
| @each $name, $color in $colors-alt { | |||
| @include custom-control-input-variant($name, $color); | |||
| } | |||
| } | |||
| @@ -0,0 +1,165 @@ | |||
| // | |||
| // Component: Info Box | |||
| // | |||
| .info-box { | |||
| @include box-shadow($card-shadow); | |||
| @include border-radius($border-radius); | |||
| background-color: $white; | |||
| display: flex; | |||
| margin-bottom: map-get($spacers, 3); | |||
| min-height: 80px; | |||
| padding: .5rem; | |||
| position: relative; | |||
| width: 100%; | |||
| .progress { | |||
| background-color: rgba($black, .125); | |||
| height: 2px; | |||
| margin: 5px 0; | |||
| .progress-bar { | |||
| background-color: $white; | |||
| } | |||
| } | |||
| .info-box-icon { | |||
| @if $enable-rounded { | |||
| border-radius: $border-radius; | |||
| } | |||
| align-items: center; | |||
| display: flex; | |||
| font-size: 1.875rem; | |||
| justify-content: center; | |||
| text-align: center; | |||
| width: 70px; | |||
| > img { | |||
| max-width: 100%; | |||
| } | |||
| } | |||
| .info-box-content { | |||
| display: flex; | |||
| flex-direction: column; | |||
| justify-content: center; | |||
| line-height: 1.8; | |||
| flex: 1; | |||
| padding: 0 10px; | |||
| } | |||
| .info-box-number { | |||
| display: block; | |||
| margin-top: .25rem; | |||
| font-weight: $font-weight-bold; | |||
| } | |||
| .progress-description, | |||
| .info-box-text { | |||
| display: block; | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| white-space: nowrap; | |||
| } | |||
| @each $name, $color in $theme-colors { | |||
| .info-box { | |||
| .bg-#{$name}, | |||
| .bg-gradient-#{$name} { | |||
| color: color-yiq($color); | |||
| .progress-bar { | |||
| background-color: color-yiq($color); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .info-box-more { | |||
| display: block; | |||
| } | |||
| .progress-description { | |||
| margin: 0; | |||
| } | |||
| @include media-breakpoint-up(md) { | |||
| .col-xl-2 &, | |||
| .col-lg-2 &, | |||
| .col-md-2 & { | |||
| .progress-description { | |||
| display: none; | |||
| } | |||
| } | |||
| .col-xl-3 &, | |||
| .col-lg-3 &, | |||
| .col-md-3 & { | |||
| .progress-description { | |||
| display: none; | |||
| } | |||
| } | |||
| } | |||
| @include media-breakpoint-up(lg) { | |||
| .col-xl-2 &, | |||
| .col-lg-2 &, | |||
| .col-md-2 & { | |||
| .progress-description { | |||
| @include font-size(.75rem); | |||
| display: block; | |||
| } | |||
| } | |||
| .col-xl-3 &, | |||
| .col-lg-3 &, | |||
| .col-md-3 & { | |||
| .progress-description { | |||
| @include font-size(.75rem); | |||
| display: block; | |||
| } | |||
| } | |||
| } | |||
| @include media-breakpoint-up(xl) { | |||
| .col-xl-2 &, | |||
| .col-lg-2 &, | |||
| .col-md-2 & { | |||
| .progress-description { | |||
| @include font-size(1rem); | |||
| display: block; | |||
| } | |||
| } | |||
| .col-xl-3 &, | |||
| .col-lg-3 &, | |||
| .col-md-3 & { | |||
| .progress-description { | |||
| @include font-size(1rem); | |||
| display: block; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .dark-mode { | |||
| .info-box { | |||
| background-color: $dark; | |||
| color: $white; | |||
| @each $name, $color in $theme-colors-alt { | |||
| .info-box { | |||
| .bg-#{$name}, | |||
| .bg-gradient-#{$name} { | |||
| color: color-yiq($color); | |||
| .progress-bar { | |||
| background-color: color-yiq($color); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,704 @@ | |||
| // | |||
| // Core: Layout | |||
| // | |||
| html.scroll-smooth { | |||
| scroll-behavior: smooth; | |||
| } | |||
| html, | |||
| body, | |||
| .wrapper { | |||
| min-height: 100%; | |||
| } | |||
| .wrapper { | |||
| position: relative; | |||
| .content-wrapper { | |||
| min-height: calc(100vh - #{$main-header-height} - #{$main-footer-height}); | |||
| } | |||
| .layout-boxed & { | |||
| @include box-shadow(0 0 10 rgba($black, .3)); | |||
| &, | |||
| &::before { | |||
| margin: 0 auto; | |||
| max-width: $boxed-layout-max-width; | |||
| } | |||
| .main-sidebar { | |||
| left: inherit; | |||
| } | |||
| } | |||
| @supports not (-webkit-touch-callout: none) { | |||
| .layout-fixed & .sidebar { | |||
| height: calc(100vh - (#{$main-header-height-inner} + #{$main-header-bottom-border-width})); | |||
| } | |||
| .layout-fixed.text-sm & .sidebar { | |||
| height: calc(100vh - (#{$main-header-height-sm-inner} + #{$main-header-bottom-border-width})); | |||
| } | |||
| } | |||
| .layout-navbar-fixed.layout-fixed & { | |||
| .control-sidebar { | |||
| top: $main-header-height; | |||
| } | |||
| .main-header.text-sm ~ .control-sidebar { | |||
| top: $main-header-height-sm; | |||
| } | |||
| .sidebar { | |||
| margin-top: $main-header-height; | |||
| } | |||
| .brand-link.text-sm ~ .sidebar { | |||
| margin-top: $main-header-height-sm; | |||
| } | |||
| } | |||
| .layout-navbar-fixed.layout-fixed.text-sm & { | |||
| .control-sidebar { | |||
| top: $main-header-height-sm; | |||
| } | |||
| .sidebar { | |||
| margin-top: $main-header-height-sm; | |||
| } | |||
| } | |||
| .layout-navbar-fixed.sidebar-mini.sidebar-collapse &, | |||
| .layout-navbar-fixed.sidebar-mini-md.sidebar-collapse &, | |||
| .layout-navbar-fixed.sidebar-mini-xs.sidebar-collapse & { | |||
| .brand-link { | |||
| height: $main-header-height; | |||
| width: $sidebar-mini-width; | |||
| &.text-sm { | |||
| height: $main-header-height-sm; | |||
| } | |||
| } | |||
| } | |||
| .layout-navbar-fixed.sidebar-mini.sidebar-collapse.text-sm &, | |||
| .layout-navbar-fixed.sidebar-mini-md.sidebar-collapse.text-sm &, | |||
| .layout-navbar-fixed.sidebar-mini-xs.sidebar-collapse.text-sm & { | |||
| .brand-link { | |||
| height: $main-header-height-sm; | |||
| } | |||
| } | |||
| body:not(.layout-fixed).layout-navbar-fixed & { | |||
| .main-sidebar { | |||
| // margin-top: calc(#{$main-header-height} / -1); | |||
| // .sidebar { | |||
| // margin-top: $main-header-height; | |||
| // } | |||
| } | |||
| } | |||
| body:not(.layout-fixed).layout-navbar-fixed.text-sm & { | |||
| .main-sidebar { | |||
| margin-top: calc(#{$main-header-height-sm} / -1); | |||
| .sidebar { | |||
| margin-top: $main-header-height-sm; | |||
| } | |||
| } | |||
| } | |||
| .layout-navbar-fixed & { | |||
| .control-sidebar { | |||
| top: 0; | |||
| } | |||
| a.anchor { | |||
| display: block; | |||
| position: relative; | |||
| top: calc((#{$main-header-height-inner} + #{$main-header-bottom-border-width} + (#{$main-header-link-padding-y} * 2)) / -1); | |||
| } | |||
| .main-sidebar:hover { | |||
| .brand-link { | |||
| transition: width $transition-speed $transition-fn; | |||
| width: $sidebar-width; | |||
| } | |||
| } | |||
| .brand-link { | |||
| overflow: hidden; | |||
| position: fixed; | |||
| top: 0; | |||
| transition: width $transition-speed $transition-fn; | |||
| width: $sidebar-width; | |||
| z-index: $zindex-main-header + 1; | |||
| } | |||
| // Sidebar variants brand-link fix | |||
| @each $name, $color in $theme-colors { | |||
| .sidebar-dark-#{$name} .brand-link:not([class*="navbar"]) { | |||
| background-color: $sidebar-dark-bg; | |||
| } | |||
| .sidebar-light-#{$name} .brand-link:not([class*="navbar"]) { | |||
| background-color: $sidebar-light-bg; | |||
| } | |||
| } | |||
| .content-wrapper { | |||
| margin-top: $main-header-height; | |||
| } | |||
| .main-header.text-sm ~ .content-wrapper { | |||
| margin-top: $main-header-height-sm; | |||
| } | |||
| .main-header { | |||
| left: 0; | |||
| position: fixed; | |||
| right: 0; | |||
| top: 0; | |||
| z-index: $zindex-main-header - 1; | |||
| } | |||
| } | |||
| .layout-navbar-fixed.text-sm & { | |||
| .content-wrapper { | |||
| margin-top: $main-header-height-sm; | |||
| } | |||
| } | |||
| .layout-navbar-not-fixed & { | |||
| .brand-link { | |||
| position: static; | |||
| } | |||
| .sidebar, | |||
| .content-wrapper { | |||
| margin-top: 0; | |||
| } | |||
| .main-header { | |||
| position: static; | |||
| } | |||
| } | |||
| .layout-navbar-not-fixed.layout-fixed & { | |||
| .sidebar { | |||
| margin-top: 0; | |||
| } | |||
| } | |||
| @each $breakpoint in map-keys($grid-breakpoints) { | |||
| @include media-breakpoint-up($breakpoint) { | |||
| $infix: breakpoint-infix($breakpoint, $grid-breakpoints); | |||
| .layout#{$infix}-navbar-fixed.layout-fixed & { | |||
| .control-sidebar { | |||
| top: $main-header-height; | |||
| } | |||
| .text-sm & .main-header ~ .control-sidebar, | |||
| .main-header.text-sm ~ .control-sidebar { | |||
| top: $main-header-height-sm; | |||
| } | |||
| .sidebar { | |||
| margin-top: $main-header-height; | |||
| } | |||
| .text-sm & .brand-link ~ .sidebar, | |||
| .brand-link.text-sm ~ .sidebar { | |||
| margin-top: $main-header-height-sm; | |||
| } | |||
| } | |||
| .layout#{$infix}-navbar-fixed.layout-fixed.text-sm & { | |||
| .control-sidebar { | |||
| top: $main-header-height-sm; | |||
| } | |||
| .sidebar { | |||
| margin-top: $main-header-height-sm; | |||
| } | |||
| } | |||
| .layout#{$infix}-navbar-fixed & { | |||
| .control-sidebar { | |||
| top: 0; | |||
| } | |||
| a.anchor { | |||
| display: block; | |||
| position: relative; | |||
| top: calc((#{$main-header-height-inner} + #{$main-header-bottom-border-width} + (#{$main-header-link-padding-y} * 2)) / -1); | |||
| } | |||
| &.sidebar-collapse { | |||
| .brand-link { | |||
| height: $main-header-height; | |||
| transition: width $transition-speed $transition-fn; | |||
| width: $sidebar-mini-width; | |||
| .text-sm &, | |||
| &.text-sm { | |||
| height: $main-header-height-sm; | |||
| } | |||
| } | |||
| .main-sidebar:hover { | |||
| .brand-link { | |||
| transition: width $transition-speed $transition-fn; | |||
| width: $sidebar-width; | |||
| } | |||
| } | |||
| } | |||
| .brand-link { | |||
| overflow: hidden; | |||
| position: fixed; | |||
| top: 0; | |||
| transition: width $transition-speed $transition-fn; | |||
| width: $sidebar-width; | |||
| z-index: $zindex-main-header + 1; | |||
| } | |||
| // Sidebar variants brand-link fix | |||
| @each $name, $color in $theme-colors { | |||
| .sidebar-dark-#{$name} .brand-link:not([class*="navbar"]) { | |||
| background-color: $sidebar-dark-bg; | |||
| } | |||
| .sidebar-light-#{$name} .brand-link:not([class*="navbar"]) { | |||
| background-color: $sidebar-light-bg; | |||
| } | |||
| } | |||
| .content-wrapper { | |||
| margin-top: $main-header-height; | |||
| } | |||
| .text-sm & .main-header ~ .content-wrapper, | |||
| .main-header.text-sm ~ .content-wrapper { | |||
| margin-top: $main-header-height-sm; | |||
| } | |||
| .main-header { | |||
| left: 0; | |||
| position: fixed; | |||
| right: 0; | |||
| top: 0; | |||
| z-index: $zindex-main-sidebar - 1; | |||
| } | |||
| } | |||
| .layout#{$infix}-navbar-fixed.text-sm & { | |||
| .content-wrapper { | |||
| margin-top: $main-header-height-sm; | |||
| } | |||
| } | |||
| body:not(.layout-fixed).layout#{$infix}-navbar-fixed & { | |||
| // .main-sidebar { | |||
| // margin-top: calc(#{$main-header-height} / -1); | |||
| // .sidebar { | |||
| // margin-top: $main-header-height; | |||
| // } | |||
| // } | |||
| } | |||
| body:not(.layout-fixed).layout#{$infix}-navbar-fixed.text-sm & { | |||
| .main-sidebar { | |||
| margin-top: calc(#{$main-header-height-sm} / -1); | |||
| .sidebar { | |||
| margin-top: $main-header-height-sm; | |||
| } | |||
| } | |||
| } | |||
| .layout#{$infix}-navbar-not-fixed & { | |||
| .brand-link { | |||
| position: static; | |||
| } | |||
| .sidebar, | |||
| .content-wrapper { | |||
| margin-top: 0; | |||
| } | |||
| .main-header { | |||
| position: static; | |||
| } | |||
| } | |||
| .layout#{$infix}-navbar-not-fixed.layout-fixed & { | |||
| .sidebar { | |||
| margin-top: 0; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .layout-footer-fixed & { | |||
| .control-sidebar { | |||
| bottom: 0; | |||
| } | |||
| .main-footer { | |||
| bottom: 0; | |||
| left: 0; | |||
| position: fixed; | |||
| right: 0; | |||
| z-index: $zindex-main-footer; | |||
| } | |||
| } | |||
| .layout-footer-not-fixed & { | |||
| .main-footer { | |||
| position: static; | |||
| } | |||
| .content-wrapper { | |||
| margin-bottom: 0; | |||
| } | |||
| } | |||
| @each $breakpoint in map-keys($grid-breakpoints) { | |||
| @include media-breakpoint-up($breakpoint) { | |||
| $infix: breakpoint-infix($breakpoint, $grid-breakpoints); | |||
| .layout#{$infix}-footer-fixed & { | |||
| .control-sidebar { | |||
| bottom: 0; | |||
| } | |||
| .main-footer { | |||
| bottom: 0; | |||
| left: 0; | |||
| position: fixed; | |||
| right: 0; | |||
| z-index: $zindex-main-footer; | |||
| } | |||
| .content-wrapper { | |||
| padding-bottom: $main-footer-height; | |||
| } | |||
| } | |||
| .layout#{$infix}-footer-not-fixed & { | |||
| .main-footer { | |||
| position: static; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .layout-top-nav & { | |||
| margin-left: 0; | |||
| .main-header { | |||
| .brand-image { | |||
| margin-top: -.5rem; | |||
| margin-right: .2rem; | |||
| height: 33px; | |||
| } | |||
| } | |||
| .main-sidebar { | |||
| bottom: inherit; | |||
| height: inherit; | |||
| } | |||
| .content-wrapper, | |||
| .main-header, | |||
| .main-footer { | |||
| margin-left: 0; | |||
| } | |||
| } | |||
| } | |||
| body.sidebar-collapse:not(.sidebar-mini-xs):not(.sidebar-mini-md):not(.sidebar-mini) { | |||
| .content-wrapper, | |||
| .main-footer, | |||
| .main-header { | |||
| &, | |||
| &::before { | |||
| margin-left: 0; | |||
| } | |||
| } | |||
| } | |||
| body:not(.sidebar-mini-md):not(.sidebar-mini-xs):not(.layout-top-nav) { | |||
| .content-wrapper, | |||
| .main-footer, | |||
| .main-header { | |||
| @include media-breakpoint-up(md) { | |||
| @include transition(margin-left $transition-speed $transition-fn); | |||
| margin-left: $sidebar-width; | |||
| .sidebar-collapse & { | |||
| margin-left: 0; | |||
| } | |||
| } | |||
| @include media-breakpoint-down(md) { | |||
| margin-left: 0; | |||
| } | |||
| } | |||
| } | |||
| .sidebar-mini-md { | |||
| .content-wrapper, | |||
| .main-footer, | |||
| .main-header { | |||
| @include media-breakpoint-up(md) { | |||
| @include transition(margin-left $transition-speed $transition-fn); | |||
| margin-left: $sidebar-width; | |||
| .sidebar-collapse & { | |||
| margin-left: $sidebar-mini-width; | |||
| } | |||
| } | |||
| @include media-breakpoint-down(md) { | |||
| margin-left: $sidebar-mini-width; | |||
| } | |||
| @include media-breakpoint-down(sm) { | |||
| margin-left: 0; | |||
| } | |||
| } | |||
| } | |||
| .sidebar-mini-xs { | |||
| .content-wrapper, | |||
| .main-footer, | |||
| .main-header { | |||
| @include media-breakpoint-up(md) { | |||
| @include transition(margin-left $transition-speed $transition-fn); | |||
| margin-left: $sidebar-width; | |||
| .sidebar-collapse & { | |||
| margin-left: $sidebar-mini-width; | |||
| } | |||
| } | |||
| @include media-breakpoint-down(md) { | |||
| margin-left: $sidebar-mini-width; | |||
| } | |||
| } | |||
| } | |||
| .content-wrapper { | |||
| background-color: $main-bg; | |||
| > .content { | |||
| padding: $content-padding-y $content-padding-x; | |||
| } | |||
| } | |||
| .main-sidebar { | |||
| &, | |||
| &::before { | |||
| $local-sidebar-transition: margin-left $transition-speed $transition-fn, width $transition-speed $transition-fn; | |||
| @include transition($local-sidebar-transition); | |||
| width: $sidebar-width; | |||
| } | |||
| .sidebar-collapse:not(.sidebar-mini):not(.sidebar-mini-md):not(.sidebar-mini-xs) & { | |||
| &, | |||
| &::before { | |||
| box-shadow: none !important; | |||
| } | |||
| } | |||
| .sidebar-collapse & { | |||
| &, | |||
| &::before { | |||
| margin-left: -$sidebar-width; | |||
| } | |||
| .nav-sidebar.nav-child-indent .nav-treeview { | |||
| padding: 0; | |||
| } | |||
| } | |||
| @include media-breakpoint-down(sm) { | |||
| &, | |||
| &::before { | |||
| box-shadow: none !important; | |||
| margin-left: -$sidebar-width; | |||
| } | |||
| .sidebar-open & { | |||
| &, | |||
| &::before { | |||
| margin-left: 0; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| body:not(.layout-fixed) { | |||
| .main-sidebar { | |||
| height: inherit; | |||
| min-height: 100%; | |||
| position: absolute; | |||
| top: 0; | |||
| .sidebar { | |||
| overflow-y: auto; | |||
| } | |||
| } | |||
| } | |||
| .layout-fixed { | |||
| .brand-link { | |||
| width: $sidebar-width; | |||
| } | |||
| .main-sidebar { | |||
| bottom: 0; | |||
| float: none; | |||
| left: 0; | |||
| position: fixed; | |||
| top: 0; | |||
| } | |||
| .control-sidebar { | |||
| bottom: 0; | |||
| float: none; | |||
| position: fixed; | |||
| top: 0; | |||
| .control-sidebar-content { | |||
| height: calc(100vh - #{$main-header-height}); | |||
| overflow-y: auto; | |||
| @include scrollbar-width-thin(); | |||
| } | |||
| } | |||
| } | |||
| @supports (-webkit-touch-callout: none) { | |||
| .layout-fixed { | |||
| .main-sidebar { | |||
| height: inherit; | |||
| } | |||
| } | |||
| } | |||
| .main-footer { | |||
| background-color: $main-footer-bg; | |||
| border-top: $main-footer-border-top; | |||
| color: lighten($gray-700, 25%); | |||
| padding: $main-footer-padding; | |||
| .text-sm &, | |||
| &.text-sm { | |||
| padding: $main-footer-padding-sm; | |||
| } | |||
| } | |||
| .content-header { | |||
| padding: 15px $content-padding-x; | |||
| .text-sm & { | |||
| padding: 10px $content-padding-x; | |||
| } | |||
| h1 { | |||
| font-size: 1.8rem; | |||
| margin: 0; | |||
| .text-sm & { | |||
| font-size: 1.5rem; | |||
| } | |||
| } | |||
| .breadcrumb { | |||
| background-color: transparent; | |||
| line-height: 1.8rem; | |||
| margin-bottom: 0; | |||
| padding: 0; | |||
| .text-sm & { | |||
| line-height: 1.5rem; | |||
| } | |||
| } | |||
| } | |||
| .hold-transition { | |||
| .content-wrapper, | |||
| .main-header, | |||
| .main-sidebar, | |||
| .main-sidebar *, | |||
| .control-sidebar, | |||
| .control-sidebar *, | |||
| .main-footer { | |||
| transition: none !important; | |||
| animation-duration: 0s !important; | |||
| } | |||
| } | |||
| .dark-mode { | |||
| background-color: $dark-main-bg; | |||
| color: $white; | |||
| .wrapper { | |||
| .layout-navbar-fixed & { | |||
| @each $name, $color in $theme-colors-alt { | |||
| .sidebar-dark-#{$name} .brand-link:not([class*="navbar"]) { | |||
| background-color: $sidebar-dark-bg; | |||
| } | |||
| .sidebar-light-#{$name} .brand-link:not([class*="navbar"]) { | |||
| background-color: $sidebar-light-bg; | |||
| } | |||
| } | |||
| } | |||
| @each $breakpoint in map-keys($grid-breakpoints) { | |||
| @include media-breakpoint-up($breakpoint) { | |||
| $infix: breakpoint-infix($breakpoint, $grid-breakpoints); | |||
| .layout#{$infix}-navbar-fixed & { | |||
| @each $name, $color in $theme-colors-alt { | |||
| .sidebar-dark-#{$name} .brand-link:not([class*="navbar"]) { | |||
| background-color: $sidebar-dark-bg; | |||
| } | |||
| .sidebar-light-#{$name} .brand-link:not([class*="navbar"]) { | |||
| background-color: $sidebar-light-bg; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .breadcrumb-item { | |||
| &.active, | |||
| + .breadcrumb-item::before { | |||
| color: $gray-500; | |||
| } | |||
| } | |||
| .main-footer { | |||
| background-color: $dark; | |||
| border-color: lighten($dark, 10%); | |||
| } | |||
| .content-wrapper { | |||
| background-color: lighten($dark, 7.5%); | |||
| color: $white; | |||
| .content-header { | |||
| color: $white; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,179 @@ | |||
| // | |||
| // Component: Main Header | |||
| // | |||
| .main-header { | |||
| border-bottom: $main-header-bottom-border; | |||
| z-index: $zindex-main-header; | |||
| .nav-link { | |||
| height: $nav-link-height; | |||
| position: relative; | |||
| } | |||
| .text-sm &, | |||
| &.text-sm { | |||
| .nav-link { | |||
| height: $nav-link-sm-height; | |||
| padding: $nav-link-sm-padding-y $nav-link-padding-x; | |||
| > .fa, | |||
| > .fas, | |||
| > .far, | |||
| > .fab, | |||
| > .fal, | |||
| > .fad, | |||
| > .svg-inline--fa, | |||
| > .ion { | |||
| font-size: $font-size-sm; | |||
| } | |||
| } | |||
| } | |||
| .navbar-nav { | |||
| .nav-item { | |||
| margin: 0; | |||
| } | |||
| &[class*="-right"] { | |||
| .dropdown-menu { | |||
| left: auto; | |||
| margin-top: -3px; | |||
| right: 0; | |||
| @media (max-width: breakpoint-max(xs)) { | |||
| left: 0; | |||
| right: auto; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| &.dropdown-legacy .dropdown-menu { | |||
| top: $nav-link-height + $navbar-padding-y; | |||
| margin-top: 0; | |||
| } | |||
| } | |||
| // Add this class to images within a nav-link | |||
| .navbar-img { | |||
| height: $main-header-height / 2; | |||
| width: auto; | |||
| } | |||
| // Navbar badge | |||
| .navbar-badge { | |||
| font-size: .6rem; | |||
| font-weight: 300; | |||
| padding: 2px 4px; | |||
| position: absolute; | |||
| right: 5px; | |||
| top: 9px; | |||
| } | |||
| .btn-navbar { | |||
| background-color: transparent; | |||
| border-left-width: 0; | |||
| } | |||
| .form-control-navbar { | |||
| border-right-width: 0; | |||
| + .input-group-append { | |||
| margin-left: 0; | |||
| } | |||
| } | |||
| .form-control-navbar, | |||
| .btn-navbar { | |||
| transition: none; | |||
| } | |||
| .navbar-dark { | |||
| .form-control-navbar, | |||
| .btn-navbar { | |||
| background-color: $main-header-dark-form-control-bg; | |||
| border-color: $main-header-dark-form-control-border-color; | |||
| } | |||
| .form-control-navbar { | |||
| &::placeholder { | |||
| color: $main-header-dark-placeholder-color; | |||
| } | |||
| + .input-group-append > .btn-navbar { | |||
| color: $main-header-dark-placeholder-color; | |||
| } | |||
| &:focus { | |||
| &, | |||
| + .input-group-append .btn-navbar { | |||
| background-color: $main-header-dark-form-control-focused-bg; | |||
| border-color: $main-header-dark-form-control-focused-border-color !important; | |||
| color: $main-header-dark-form-control-focused-color; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .navbar-light { | |||
| .form-control-navbar, | |||
| .btn-navbar { | |||
| background-color: $main-header-light-form-control-bg; | |||
| border-color: $main-header-light-form-control-border-color; | |||
| } | |||
| .form-control-navbar { | |||
| &::placeholder { | |||
| color: $main-header-light-placeholder-color; | |||
| } | |||
| + .input-group-append > .btn-navbar { | |||
| color: $main-header-light-placeholder-color; | |||
| } | |||
| &:focus { | |||
| &, | |||
| + .input-group-append .btn-navbar { | |||
| background-color: $main-header-light-form-control-focused-bg; | |||
| border-color: $main-header-light-form-control-focused-border-color !important; | |||
| color: $main-header-light-form-control-focused-color; | |||
| } | |||
| } | |||
| } | |||
| .navbar-search-block { | |||
| .form-control-navbar { | |||
| &:focus { | |||
| &, | |||
| + .input-group-append .btn-navbar { | |||
| color: $main-header-light-placeholder-color; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // Navbar Search | |||
| .navbar-search-block { | |||
| position: absolute; | |||
| padding: 0 $nav-link-padding-x; | |||
| left: 0; | |||
| top: 0; | |||
| right: 0; | |||
| bottom: 0; | |||
| z-index: 10; | |||
| display: none; | |||
| justify-content: center; | |||
| flex-direction: column; | |||
| background-color: initial; | |||
| &.navbar-search-open { | |||
| display: flex; | |||
| } | |||
| .input-group { | |||
| width: 100%; | |||
| } | |||
| } | |||
| @@ -0,0 +1,541 @@ | |||
| // | |||
| // Misc: Miscellaneous | |||
| // | |||
| .border-transparent { | |||
| border-color: transparent !important; | |||
| } | |||
| // Description Blocks | |||
| .description-block { | |||
| display: block; | |||
| margin: 10px 0; | |||
| text-align: center; | |||
| &.margin-bottom { | |||
| margin-bottom: 25px; | |||
| } | |||
| > .description-header { | |||
| font-size: 16px; | |||
| font-weight: 600; | |||
| margin: 0; | |||
| padding: 0; | |||
| } | |||
| > .description-text { | |||
| text-transform: uppercase; | |||
| } | |||
| // Description Block Extension | |||
| .description-icon { | |||
| font-size: 16px; | |||
| } | |||
| } | |||
| // List utility classes | |||
| .list-group-unbordered { | |||
| > .list-group-item { | |||
| border-left: 0; | |||
| border-radius: 0; | |||
| border-right: 0; | |||
| padding-left: 0; | |||
| padding-right: 0; | |||
| } | |||
| } | |||
| .list-header { | |||
| color: $gray-600; | |||
| font-size: 15px; | |||
| font-weight: 700; | |||
| padding: 10px 4px; | |||
| } | |||
| .list-seperator { | |||
| background-color: $card-border-color; | |||
| height: 1px; | |||
| margin: 15px 0 9px; | |||
| } | |||
| .list-link { | |||
| > a { | |||
| color: $gray-600; | |||
| padding: 4px; | |||
| &:hover { | |||
| color: $gray-900; | |||
| } | |||
| } | |||
| } | |||
| // User block | |||
| .user-block { | |||
| float: left; | |||
| img { | |||
| float: left; | |||
| height: 40px; | |||
| width: 40px; | |||
| } | |||
| .username, | |||
| .description, | |||
| .comment { | |||
| display: block; | |||
| margin-left: 50px; | |||
| } | |||
| .username { | |||
| font-size: 16px; | |||
| font-weight: 600; | |||
| margin-top: -1px; | |||
| } | |||
| .description { | |||
| color: $gray-600; | |||
| font-size: 13px; | |||
| margin-top: -3px; | |||
| } | |||
| &.user-block-sm { | |||
| img { | |||
| width: $img-size-sm; | |||
| height: $img-size-sm; | |||
| } | |||
| .username, | |||
| .description, | |||
| .comment { | |||
| margin-left: 40px; | |||
| } | |||
| .username { | |||
| font-size: 14px; | |||
| } | |||
| } | |||
| } | |||
| // Image sizes | |||
| .img-sm, | |||
| .img-md, | |||
| .img-lg { | |||
| float: left; | |||
| } | |||
| .img-sm { | |||
| height: $img-size-sm; | |||
| width: $img-size-sm; | |||
| + .img-push { | |||
| margin-left: $img-size-sm + $img-size-push; | |||
| } | |||
| } | |||
| .img-md { | |||
| width: $img-size-md; | |||
| height: $img-size-md; | |||
| + .img-push { | |||
| margin-left: $img-size-md + $img-size-push; | |||
| } | |||
| } | |||
| .img-lg { | |||
| width: $img-size-lg; | |||
| height: $img-size-lg; | |||
| + .img-push { | |||
| margin-left: $img-size-lg + $img-size-push; | |||
| } | |||
| } | |||
| // Image bordered | |||
| .img-bordered { | |||
| border: 3px solid $gray-500; | |||
| padding: 3px; | |||
| } | |||
| .img-bordered-sm { | |||
| border: 2px solid $gray-500; | |||
| padding: 2px; | |||
| } | |||
| // Rounded and Circle Images | |||
| .img-rounded { | |||
| @include border-radius($border-radius); | |||
| } | |||
| .img-circle { | |||
| @include border-radius(50%); | |||
| } | |||
| // Image sizes | |||
| .img-size-64, | |||
| .img-size-50, | |||
| .img-size-32 { | |||
| height: auto; | |||
| } | |||
| .img-size-64 { | |||
| width: 64px; | |||
| } | |||
| .img-size-50 { | |||
| width: 50px; | |||
| } | |||
| .img-size-32 { | |||
| width: 32px; | |||
| } | |||
| // Block sizes | |||
| .size-32, | |||
| .size-40, | |||
| .size-50 { | |||
| display: block; | |||
| text-align: center; | |||
| } | |||
| .size-32 { | |||
| height: 32px; | |||
| line-height: 32px; | |||
| width: 32px; | |||
| } | |||
| .size-40 { | |||
| height: 40px; | |||
| line-height: 40px; | |||
| width: 40px; | |||
| } | |||
| .size-50 { | |||
| height: 50px; | |||
| line-height: 50px; | |||
| width: 50px; | |||
| } | |||
| // General attachemnt block | |||
| .attachment-block { | |||
| background-color: $gray-100; | |||
| border: 1px solid $card-border-color; | |||
| margin-bottom: 10px; | |||
| padding: 5px; | |||
| .attachment-img { | |||
| float: left; | |||
| height: auto; | |||
| max-height: 100px; | |||
| max-width: 100px; | |||
| } | |||
| .attachment-pushed { | |||
| margin-left: 110px; | |||
| } | |||
| .attachment-heading { | |||
| margin: 0; | |||
| } | |||
| .attachment-text { | |||
| color: $gray-700; | |||
| } | |||
| } | |||
| // Overlays for Card, InfoBox & SmallBox | |||
| .card, | |||
| .overlay-wrapper, | |||
| .info-box, | |||
| .small-box { | |||
| // Box overlay for LOADING STATE effect | |||
| > .overlay, | |||
| > .loading-img { | |||
| height: 100%; | |||
| left: 0; | |||
| position: absolute; | |||
| top: 0; | |||
| width: 100%; | |||
| } | |||
| .overlay { | |||
| @include border-radius($border-radius); | |||
| align-items: center; | |||
| background-color: rgba($white, .7); | |||
| display: flex; | |||
| justify-content: center; | |||
| z-index: 50; | |||
| > .fa, | |||
| > .fas, | |||
| > .far, | |||
| > .fab, | |||
| > .fal, | |||
| > .fad, | |||
| > .svg-inline--fa, | |||
| > .ion { | |||
| color: $gray-800; | |||
| } | |||
| &.dark { | |||
| background-color: rgba($black, .5); | |||
| > .fa, | |||
| > .fas, | |||
| > .far, | |||
| > .fab, | |||
| > .fal, | |||
| > .fad, | |||
| > .svg-inline--fa, | |||
| > .ion { | |||
| color: $gray-400; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .tab-pane { | |||
| // Box overlay for LOADING STATE effect on Tab Panels | |||
| > .overlay-wrapper { | |||
| position: relative; | |||
| > .overlay { | |||
| border-top-left-radius: 0; | |||
| border-top-right-radius: 0; | |||
| flex-direction: column; | |||
| margin-top: -$card-spacer-x; | |||
| margin-left: -$card-spacer-x; | |||
| height: calc(100% + 2 * #{$card-spacer-x}); | |||
| width: calc(100% + 2 * #{$card-spacer-x}); | |||
| &.dark { | |||
| color: $white; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // Ribbon | |||
| .ribbon-wrapper { | |||
| height: $ribbon-wrapper-size; | |||
| overflow: hidden; | |||
| position: absolute; | |||
| right: -2px; | |||
| top: -2px; | |||
| width: $ribbon-wrapper-size; | |||
| z-index: 10; | |||
| &.ribbon-lg { | |||
| height: $ribbon-lg-wrapper-size; | |||
| width: $ribbon-lg-wrapper-size; | |||
| .ribbon { | |||
| right: $ribbon-lg-right; | |||
| top: $ribbon-lg-top; | |||
| width: $ribbon-lg-width; | |||
| } | |||
| } | |||
| &.ribbon-xl { | |||
| height: $ribbon-xl-wrapper-size; | |||
| width: $ribbon-xl-wrapper-size; | |||
| .ribbon { | |||
| right: $ribbon-xl-right; | |||
| top: $ribbon-xl-top; | |||
| width: $ribbon-xl-width; | |||
| } | |||
| } | |||
| .ribbon { | |||
| box-shadow: 0 0 $ribbon-border-size rgba($black, .3); | |||
| font-size: $ribbon-font-size; | |||
| line-height: $ribbon-line-height; | |||
| padding: $ribbon-padding; | |||
| position: relative; | |||
| right: $ribbon-right; | |||
| text-align: center; | |||
| text-shadow: 0 -1px 0 rgba($black, .4); | |||
| text-transform: uppercase; | |||
| top: $ribbon-top; | |||
| transform: rotate(45deg); | |||
| width: $ribbon-width; | |||
| &::before, | |||
| &::after { | |||
| border-left: $ribbon-border-size solid transparent; | |||
| border-right: $ribbon-border-size solid transparent; | |||
| border-top: $ribbon-border-size solid #9e9e9e; | |||
| bottom: -$ribbon-border-size; | |||
| content: ""; | |||
| position: absolute; | |||
| } | |||
| &::before { | |||
| left: 0; | |||
| } | |||
| &::after { | |||
| right: 0; | |||
| } | |||
| } | |||
| } | |||
| // Scroll To Top | |||
| .back-to-top { | |||
| bottom: 1.25rem; | |||
| position: fixed; | |||
| right: 1.25rem; | |||
| z-index: $zindex-control-sidebar + 1; | |||
| &:focus { | |||
| box-shadow: none; | |||
| } | |||
| } | |||
| // Pre | |||
| pre { | |||
| padding: .75rem; | |||
| } | |||
| // Blockquotes styles | |||
| blockquote { | |||
| background-color: $white; | |||
| border-left: .7rem solid $primary; | |||
| margin: 1.5em .7rem; | |||
| padding: .5em .7rem; | |||
| .box & { | |||
| background-color: $gray-200; | |||
| } | |||
| p:last-child { | |||
| margin-bottom: 0; | |||
| } | |||
| h1, | |||
| h2, | |||
| h3, | |||
| h4, | |||
| h5, | |||
| h6 { | |||
| color: $primary; | |||
| font-size: 1.25rem; | |||
| font-weight: 600; | |||
| } | |||
| @each $color, $value in $theme-colors { | |||
| &.quote-#{$color} { | |||
| border-color: $value; | |||
| h1, | |||
| h2, | |||
| h3, | |||
| h4, | |||
| h5, | |||
| h6 { | |||
| color: $value; | |||
| } | |||
| } | |||
| } | |||
| @each $color, $value in $colors { | |||
| &.quote-#{$color} { | |||
| border-color: $value; | |||
| h1, | |||
| h2, | |||
| h3, | |||
| h4, | |||
| h5, | |||
| h6 { | |||
| color: $value; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // Tab Custom Content | |||
| .tab-custom-content { | |||
| border-top: $nav-tabs-border-width solid $nav-tabs-border-color; | |||
| margin-top: .5rem; | |||
| padding-top: .5rem; | |||
| } | |||
| .nav + .tab-custom-content { | |||
| border-top: none; | |||
| border-bottom: $nav-tabs-border-width solid $nav-tabs-border-color; | |||
| margin-top: 0; | |||
| margin-bottom: .5rem; | |||
| padding-bottom: .5rem; | |||
| } | |||
| // Badge BTN Style | |||
| .badge-btn { | |||
| border-radius: $button-border-radius-xs; | |||
| font-size: $button-font-size-xs; | |||
| font-weight: 400; | |||
| padding: $button-padding-y-xs * 2 $button-padding-x-xs * 2; | |||
| } | |||
| .badge-btn.badge-pill { | |||
| padding: .375rem .6rem; | |||
| } | |||
| .dark-mode { | |||
| a:not(.btn):hover { | |||
| color: lighten($link-color, 10%); | |||
| } | |||
| .attachment-block { | |||
| background-color: lighten($dark, 3.75%); | |||
| .attachment-text { | |||
| color: $gray-400; | |||
| } | |||
| } | |||
| blockquote { | |||
| background-color: lighten($dark, 5%); | |||
| @each $color, $value in $theme-colors { | |||
| &.quote-#{$color} { | |||
| border-color: $value; | |||
| h1, | |||
| h2, | |||
| h3, | |||
| h4, | |||
| h5, | |||
| h6 { | |||
| color: $value; | |||
| } | |||
| } | |||
| } | |||
| @each $color, $value in $colors { | |||
| &.quote-#{$color} { | |||
| border-color: $value; | |||
| h1, | |||
| h2, | |||
| h3, | |||
| h4, | |||
| h5, | |||
| h6 { | |||
| color: $value; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .close, | |||
| .mailbox-attachment-close { | |||
| color: $gray-500; | |||
| text-shadow: 0 1px 0 $gray-700; | |||
| } | |||
| .tab-custom-content { | |||
| border-color: $gray-600; | |||
| } | |||
| .list-group-item { | |||
| background-color: $dark; | |||
| border-color: $gray-600; | |||
| } | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| // | |||
| // General: Mixins | |||
| // | |||
| @import "mixins/animations"; | |||
| @import "mixins/cards"; | |||
| @import "mixins/sidebar"; | |||
| @import "mixins/navbar"; | |||
| @import "mixins/accent"; | |||
| @import "mixins/custom-forms"; | |||
| @import "mixins/backgrounds"; | |||
| @import "mixins/direct-chat"; | |||
| @import "mixins/toasts"; | |||
| @import "mixins/touch-support"; | |||
| @import "mixins/miscellaneous"; | |||
| @@ -0,0 +1,76 @@ | |||
| // | |||
| // Component: Modals | |||
| // | |||
| // Overlay | |||
| .modal-dialog { | |||
| .overlay { | |||
| display: flex; | |||
| position: absolute; | |||
| left: 0; | |||
| top: 0; | |||
| bottom: 0; | |||
| right: 0; | |||
| margin: -$modal-content-border-width; | |||
| z-index: ($zindex-modal + 2); | |||
| justify-content: center; | |||
| align-items: center; | |||
| background-color: rgba($black, .7); | |||
| color: darken($gray-600, 2.5%); | |||
| @include border-radius($modal-content-border-radius); | |||
| } | |||
| } | |||
| // BG Color Variations Fixes | |||
| .modal-content { | |||
| &.bg-warning { | |||
| .modal-header, | |||
| .modal-footer { | |||
| border-color: $gray-800; | |||
| } | |||
| } | |||
| &.bg-primary, | |||
| &.bg-secondary, | |||
| &.bg-info, | |||
| &.bg-danger, | |||
| &.bg-success, { | |||
| .close { | |||
| color: $white; | |||
| text-shadow: 0 1px 0 $black; | |||
| } | |||
| } | |||
| } | |||
| .dark-mode { | |||
| .modal-header, | |||
| .modal-footer { | |||
| border-color: $gray-600; | |||
| } | |||
| .modal-content { | |||
| background-color: $dark; | |||
| &.bg-warning { | |||
| .modal-header, | |||
| .modal-footer { | |||
| border-color: $gray-600; | |||
| } | |||
| .close { | |||
| color: $dark !important; | |||
| text-shadow: 0 1px 0 $gray-700 !important; | |||
| } | |||
| } | |||
| &.bg-primary, | |||
| &.bg-secondary, | |||
| &.bg-info, | |||
| &.bg-danger, | |||
| &.bg-success { | |||
| .modal-header, | |||
| .modal-footer { | |||
| border-color: $white; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,168 @@ | |||
| // | |||
| // Component: Nav | |||
| // | |||
| .nav-pills { | |||
| .nav-link { | |||
| color: $gray-600; | |||
| &:not(.active):hover { | |||
| color: theme-color("primary"); | |||
| } | |||
| } | |||
| .nav-item { | |||
| &.dropdown.show { | |||
| .nav-link:hover { | |||
| color: $dropdown-link-active-color; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // Vertical Tabs | |||
| .nav-tabs.flex-column { | |||
| border-bottom: 0; | |||
| border-right: $nav-tabs-border-width solid $nav-tabs-border-color; | |||
| .nav-link { | |||
| border-bottom-left-radius: $nav-tabs-border-radius; | |||
| border-top-right-radius: 0; | |||
| margin-right: -$nav-tabs-border-width; | |||
| @include hover-focus () { | |||
| border-color: $gray-200 transparent $gray-200 $gray-200; | |||
| } | |||
| } | |||
| .nav-link.active, | |||
| .nav-item.show .nav-link { | |||
| border-color: $gray-300 transparent $gray-300 $gray-300; | |||
| } | |||
| &.nav-tabs-right { | |||
| border-left: $nav-tabs-border-width solid $nav-tabs-border-color; | |||
| border-right: 0; | |||
| .nav-link { | |||
| border-bottom-left-radius: 0; | |||
| border-bottom-right-radius: $nav-tabs-border-radius; | |||
| border-top-left-radius: 0; | |||
| border-top-right-radius: $nav-tabs-border-radius; | |||
| margin-left: -$nav-tabs-border-width; | |||
| @include hover-focus () { | |||
| border-color: $gray-200 $gray-200 $gray-200 transparent; | |||
| } | |||
| } | |||
| .nav-link.active, | |||
| .nav-item.show .nav-link { | |||
| border-color: $gray-300 $gray-300 $gray-300 transparent; | |||
| } | |||
| } | |||
| } | |||
| .navbar-no-expand { | |||
| flex-direction: row; | |||
| .nav-link { | |||
| padding-left: $navbar-nav-link-padding-x; | |||
| padding-right: $navbar-nav-link-padding-x; | |||
| } | |||
| .dropdown-menu { | |||
| position: absolute; | |||
| } | |||
| } | |||
| // Color variants | |||
| @each $color, $value in $theme-colors { | |||
| @if $color == dark or $color == light { | |||
| .navbar-#{$color} { | |||
| background-color: $value; | |||
| @if $color == dark { | |||
| border-color: lighten($dark, 10%); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @each $color, $value in $theme-colors { | |||
| @if $color != dark and $color != light { | |||
| @include navbar-variant($color, $value); | |||
| } | |||
| } | |||
| @each $color, $value in $colors { | |||
| @include navbar-variant($color, $value); | |||
| } | |||
| .dark-mode { | |||
| .nav-pills .nav-link { | |||
| color: $gray-400; | |||
| } | |||
| .nav-tabs { | |||
| border-color: lighten($dark, 15%); | |||
| .nav-link:focus, | |||
| .nav-link:hover { | |||
| border-color: lighten($dark, 15%); | |||
| } | |||
| .nav-item.show .nav-link, | |||
| .nav-link.active { | |||
| background-color: $dark; | |||
| border-color: lighten($dark, 15%) lighten($dark, 15%) transparent lighten($dark, 15%); | |||
| color: $white; | |||
| } | |||
| &.flex-column { | |||
| .nav-item.show .nav-link, | |||
| .nav-link { | |||
| &.active, | |||
| &:focus, | |||
| &:hover { | |||
| border-color: lighten($dark, 15%) transparent lighten($dark, 15%) lighten($dark, 15%); | |||
| } | |||
| &:focus, | |||
| &:hover { | |||
| background-color: lighten($dark, 5%); | |||
| } | |||
| } | |||
| &.nav-tabs-right { | |||
| border-color: lighten($dark, 15%); | |||
| .nav-link { | |||
| &.active, | |||
| &:focus, | |||
| &:hover { | |||
| border-color: lighten($dark, 15%) lighten($dark, 15%) lighten($dark, 15%) transparent; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // Color variants | |||
| @each $color, $value in $theme-colors-alt { | |||
| @if $color == dark or $color == light { | |||
| .navbar-#{$color} { | |||
| background-color: $value; | |||
| @if $color == dark { | |||
| border-color: lighten($dark, 10%); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @each $color, $value in $theme-colors-alt { | |||
| @if $color != dark and $color != light { | |||
| @include navbar-variant($color, $value); | |||
| } | |||
| } | |||
| @each $color, $value in $colors-alt { | |||
| @include navbar-variant($color, $value); | |||
| } | |||
| } | |||
| @@ -0,0 +1,82 @@ | |||
| // | |||
| // Component: Pagination | |||
| // | |||
| .pagination-month { | |||
| .page-item { | |||
| justify-self: stretch; | |||
| .page-link { | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| flex-direction: column; | |||
| box-shadow: none; | |||
| } | |||
| &:first-child, | |||
| &:last-child { | |||
| .page-link { | |||
| height: 100%; | |||
| font-size: $font-size-lg; | |||
| } | |||
| } | |||
| .page-month { | |||
| margin-bottom: 0; | |||
| font-size: $font-size-lg; | |||
| font-weight: $font-weight-bold; | |||
| } | |||
| .page-year { | |||
| margin-bottom: 0; | |||
| } | |||
| } | |||
| &.pagination-lg { | |||
| .page-month { | |||
| font-size: ($font-size-lg * 1.25); | |||
| } | |||
| } | |||
| &.pagination-sm { | |||
| .page-month { | |||
| font-size: ($font-size-base); | |||
| } | |||
| } | |||
| } | |||
| .dark-mode { | |||
| .page-item { | |||
| &.disabled a, | |||
| &.disabled .page-link { | |||
| background-color: lighten($dark, 2.5%) !important; | |||
| border-color: $gray-600 !important; | |||
| color: $gray-600; | |||
| } | |||
| .page-link { | |||
| color: $primary-alt; | |||
| } | |||
| &.active { | |||
| .page-link { | |||
| background-color: $primary-alt; | |||
| color: $white; | |||
| &:hover, | |||
| &:focus { | |||
| color: $gray-400 !important; | |||
| } | |||
| } | |||
| } | |||
| &:not(.active) { | |||
| .page-link { | |||
| background-color: $dark; | |||
| border-color: $gray-600; | |||
| &:hover, | |||
| &:focus { | |||
| color: lighten($primary-alt, 5%); | |||
| background-color: lighten($dark, 5%); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| // | |||
| // Core: Preloader | |||
| // | |||
| .preloader { | |||
| display: flex; | |||
| background-color: $main-bg; | |||
| height: 100vh; | |||
| width: 100%; | |||
| transition: height 200ms linear; | |||
| position: fixed; | |||
| left: 0; | |||
| top: 0; | |||
| z-index: $zindex-preloader; | |||
| } | |||
| .dark-mode { | |||
| .preloader { | |||
| background-color: $dark-main-bg; | |||
| color: $white; | |||
| } | |||
| } | |||
| // | |||
| @@ -0,0 +1,52 @@ | |||
| // | |||
| // Misc: Print | |||
| // | |||
| @media print { | |||
| //Add to elements that you do not want to show when printing | |||
| .no-print { | |||
| display: none !important; | |||
| } | |||
| //Elements that we want to hide when printing | |||
| .main-sidebar, | |||
| .main-header, | |||
| .content-header { | |||
| @extend .no-print; | |||
| } | |||
| //This is the only element that should appear, so let's remove the margins | |||
| .content-wrapper, | |||
| .main-footer { | |||
| @include translate(0, 0); | |||
| margin-left: 0 !important; | |||
| min-height: 0 !important; | |||
| } | |||
| .layout-fixed .content-wrapper { | |||
| padding-top: 0 !important; | |||
| } | |||
| //Invoice printing | |||
| .invoice { | |||
| border: 0; | |||
| margin: 0; | |||
| padding: 0; | |||
| width: 100%; | |||
| } | |||
| .invoice-col { | |||
| float: left; | |||
| width: 33.3333333%; | |||
| } | |||
| //Make sure table content displays properly | |||
| .table-responsive { | |||
| overflow: auto; | |||
| > .table tr th, | |||
| > .table tr td { | |||
| white-space: normal !important; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,68 @@ | |||
| // | |||
| // Component: Products | |||
| // | |||
| .products-list { | |||
| list-style: none; | |||
| margin: 0; | |||
| padding: 0; | |||
| > .item { | |||
| @include clearfix (); | |||
| @if $enable-rounded { | |||
| @include border-radius($border-radius); | |||
| } | |||
| background-color: $white; | |||
| padding: 10px 0; | |||
| } | |||
| .product-img { | |||
| float: left; | |||
| img { | |||
| height: 50px; | |||
| width: 50px; | |||
| } | |||
| } | |||
| .product-info { | |||
| margin-left: 60px; | |||
| } | |||
| .product-title { | |||
| font-weight: 600; | |||
| } | |||
| .product-description { | |||
| color: $gray-600; | |||
| display: block; | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| white-space: nowrap; | |||
| } | |||
| } | |||
| .product-list-in-card > .item { | |||
| @include border-radius(0); | |||
| border-bottom: 1px solid $card-border-color; | |||
| &:last-of-type { | |||
| border-bottom-width: 0; | |||
| } | |||
| } | |||
| .dark-mode { | |||
| .products-list > .item { | |||
| background-color: $dark; | |||
| color: $white; | |||
| border-bottom-color: $gray-600; | |||
| } | |||
| .product-description { | |||
| color: $gray-400; | |||
| } | |||
| } | |||
| @@ -0,0 +1,72 @@ | |||
| // | |||
| // Component: Progress Bar | |||
| // | |||
| //General CSS | |||
| .progress { | |||
| @include box-shadow(none); | |||
| @include border-radius($progress-bar-border-radius); | |||
| // Vertical bars | |||
| &.vertical { | |||
| display: inline-block; | |||
| height: 200px; | |||
| margin-right: 10px; | |||
| position: relative; | |||
| width: 30px; | |||
| > .progress-bar { | |||
| bottom: 0; | |||
| position: absolute; | |||
| width: 100%; | |||
| } | |||
| //Sizes | |||
| &.sm, | |||
| &.progress-sm { | |||
| width: 20px; | |||
| } | |||
| &.xs, | |||
| &.progress-xs { | |||
| width: 10px; | |||
| } | |||
| &.xxs, | |||
| &.progress-xxs { | |||
| width: 3px; | |||
| } | |||
| } | |||
| } | |||
| .progress-group { | |||
| margin-bottom: map-get($spacers, 2); | |||
| } | |||
| // size variation | |||
| .progress-sm { | |||
| height: 10px; | |||
| } | |||
| .progress-xs { | |||
| height: 7px; | |||
| } | |||
| .progress-xxs { | |||
| height: 3px; | |||
| } | |||
| // Remove margins from progress bars when put in a table | |||
| .table { | |||
| tr > td { | |||
| .progress { | |||
| margin: 0; | |||
| } | |||
| } | |||
| } | |||
| .dark-mode { | |||
| .progress { | |||
| background: lighten($dark, 7.5%); | |||
| } | |||
| } | |||